diff --git a/book/src/traits.md b/book/src/traits.md index 06b7f652a..1ba7c9cd5 100644 --- a/book/src/traits.md +++ b/book/src/traits.md @@ -120,9 +120,9 @@ let mut m = Module::with_crate("std", ["iter"]); let mut t = m.define_trait(["Iterator"])?; t.handler(|cx| { - let next = cx.find(Protocol::NEXT)?; + let next = cx.find(&Protocol::NEXT)?; - let size_hint = cx.find_or_define(Protocol::SIZE_HINT, |_: Value| (0usize, None::))?; + let size_hint = cx.find_or_define(&Protocol::SIZE_HINT, |_: Value| (0usize, None::))?; /* more methods */ Ok(()) diff --git a/crates/rune-core/src/hash.rs b/crates/rune-core/src/hash.rs index 69cc097d3..c05eca458 100644 --- a/crates/rune-core/src/hash.rs +++ b/crates/rune-core/src/hash.rs @@ -24,8 +24,6 @@ impl fmt::Display for TooManyParameters { impl core::error::Error for TooManyParameters {} -use crate::protocol::Protocol; - use crate::alloc; use crate::alloc::clone::TryClone; @@ -143,26 +141,23 @@ impl Hash { /// Construct a hash to an instance function, where the instance is a /// pre-determined type. #[inline] - pub fn associated_function(type_hash: Hash, name: N) -> Self - where - N: IntoHash, - { + pub fn associated_function(type_hash: impl IntoHash, name: impl IntoHash) -> Self { + let type_hash = type_hash.into_hash(); let name = name.into_hash(); Self(ASSOCIATED_FUNCTION_HASH ^ (type_hash.0 ^ name.0)) } /// Construct a hash corresponding to a field function. #[inline] - pub fn field_function(protocol: Protocol, type_hash: Hash, name: N) -> Self - where - N: IntoHash, - { + pub fn field_function(protocol: impl IntoHash, type_hash: Hash, name: impl IntoHash) -> Self { + let protocol = protocol.into_hash(); Self::associated_function(Hash(type_hash.0 ^ protocol.0), name) } /// Construct an index function. #[inline] - pub fn index_function(protocol: Protocol, type_hash: Hash, index: Hash) -> Self { + pub fn index_function(protocol: impl IntoHash, type_hash: Hash, index: Hash) -> Self { + let protocol = protocol.into_hash(); Self::associated_function(Hash(type_hash.0 ^ protocol.0), index) } diff --git a/crates/rune-core/src/hash/into_hash.rs b/crates/rune-core/src/hash/into_hash.rs index 55e6bdd16..f39c0841b 100644 --- a/crates/rune-core/src/hash/into_hash.rs +++ b/crates/rune-core/src/hash/into_hash.rs @@ -1,4 +1,5 @@ use crate::hash::Hash; +use crate::protocol::Protocol; mod sealed { use crate::hash::Hash; @@ -9,7 +10,7 @@ mod sealed { impl Sealed for &str {} impl Sealed for Hash {} - impl Sealed for Protocol {} + impl Sealed for &Protocol {} impl Sealed for Params {} } @@ -33,3 +34,10 @@ impl IntoHash for &str { Hash::ident(self) } } + +impl IntoHash for &Protocol { + #[inline] + fn into_hash(self) -> Hash { + self.hash + } +} diff --git a/crates/rune-core/src/protocol.rs b/crates/rune-core/src/protocol.rs index ebfe30b91..696387fed 100644 --- a/crates/rune-core/src/protocol.rs +++ b/crates/rune-core/src/protocol.rs @@ -1,19 +1,14 @@ use core::cmp; use core::fmt; use core::hash::Hasher; -use core::ops; -use crate as rune; #[cfg(feature = "alloc")] use crate::alloc; -use crate::alloc::prelude::*; -use crate::hash::IntoHash; use crate::hash::{Hash, ToTypeHash}; use crate::item::ItemBuf; /// A built in instance function. -#[derive(Debug, TryClone, Clone, Copy)] -#[try_clone(copy)] +#[derive(Debug)] #[non_exhaustive] pub struct Protocol { /// The name of the builtin function. @@ -36,14 +31,7 @@ pub struct Protocol { pub doc: &'static [&'static str], } -impl IntoHash for Protocol { - #[inline] - fn into_hash(self) -> Hash { - self.hash - } -} - -impl ToTypeHash for Protocol { +impl ToTypeHash for &Protocol { #[inline] fn to_type_hash(&self) -> Hash { self.hash @@ -56,14 +44,6 @@ impl ToTypeHash for Protocol { } } -impl ops::Deref for Protocol { - type Target = Hash; - - fn deref(&self) -> &Self::Target { - &self.hash - } -} - impl fmt::Display for Protocol { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.name) diff --git a/crates/rune-macros/src/any.rs b/crates/rune-macros/src/any.rs index 33eba406f..09dbfe961 100644 --- a/crates/rune-macros/src/any.rs +++ b/crates/rune-macros/src/any.rs @@ -477,7 +477,7 @@ fn expand_enum_install_with( } let is_variant = quote! { - module.associated_function(#protocol::IS_VARIANT, |this: &Self, index: usize| { + module.associated_function(&#protocol::IS_VARIANT, |this: &Self, index: usize| { match (this, index) { #(#is_variant,)* _ => false, @@ -489,7 +489,7 @@ fn expand_enum_install_with( for (field, matches) in field_fns { installers.push(quote! { - module.field_function(#protocol::GET, #field, |this: &Self| { + module.field_function(&#protocol::GET, #field, |this: &Self| { match this { #(#matches,)* _ => return #vm_result::err( @@ -504,7 +504,7 @@ fn expand_enum_install_with( for (index, matches) in index_fns { installers.push(quote! { - module.index_function(#protocol::GET, #index, |this: &Self| { + module.index_function(&#protocol::GET, #index, |this: &Self| { match this { #(#matches,)* _ => return #vm_result::err( diff --git a/crates/rune-macros/src/context.rs b/crates/rune-macros/src/context.rs index adddecb66..35522843f 100644 --- a/crates/rune-macros/src/context.rs +++ b/crates/rune-macros/src/context.rs @@ -278,11 +278,11 @@ impl Context { GenerateTarget::Named { field_ident, field_name } => { if let Some(custom) = &protocol.custom { quote_spanned! { field.span() => - module.field_function(#protocol_field, #field_name, #custom)?; + module.field_function(&#protocol_field, #field_name, #custom)?; } } else { quote_spanned! { field.span() => - module.field_function(#protocol_field, #field_name, |s: &mut Self, value: #ty| { + module.field_function(&#protocol_field, #field_name, |s: &mut Self, value: #ty| { s.#field_ident $op value; })?; } @@ -291,11 +291,11 @@ impl Context { GenerateTarget::Numbered { field_index } => { if let Some(custom) = &protocol.custom { quote_spanned! { field.span() => - module.index_function(#protocol_field, #field_index, #custom)?; + module.index_function(&#protocol_field, #field_index, #custom)?; } } else { quote_spanned! { field.span() => - module.index_function(#protocol_field, #field_index, |s: &mut Self, value: #ty| { + module.index_function(&#protocol_field, #field_index, |s: &mut Self, value: #ty| { s.#field_index $op value; })?; } @@ -394,7 +394,7 @@ impl Context { let protocol = g.tokens.protocol(Protocol::GET); quote_spanned! { g.field.span() => - module.field_function(#protocol, #field_name, |s: &Self| #vm_result::Ok(#access))?; + module.field_function(&#protocol, #field_name, |s: &Self| #vm_result::Ok(#access))?; } } GenerateTarget::Numbered { field_index } => { @@ -407,7 +407,7 @@ impl Context { let protocol = g.tokens.protocol(Protocol::GET); quote_spanned! { g.field.span() => - module.index_function(#protocol, #field_index, |s: &Self| #vm_result::Ok(#access))?; + module.index_function(&#protocol, #field_index, |s: &Self| #vm_result::Ok(#access))?; } } } @@ -432,14 +432,14 @@ impl Context { match target { GenerateTarget::Named { field_ident, field_name } => { quote_spanned! { g.field.span() => - module.field_function(#protocol, #field_name, |s: &mut Self, value: #ty| { + module.field_function(&#protocol, #field_name, |s: &mut Self, value: #ty| { s.#field_ident = value; })?; } } GenerateTarget::Numbered { field_index } => { quote_spanned! { g.field.span() => - module.index_function(#protocol, #field_index, |s: &mut Self, value: #ty| { + module.index_function(&#protocol, #field_index, |s: &mut Self, value: #ty| { s.#field_index = value; })?; } diff --git a/crates/rune-macros/src/function.rs b/crates/rune-macros/src/function.rs index 60225c322..e046705f7 100644 --- a/crates/rune-macros/src/function.rs +++ b/crates/rune-macros/src/function.rs @@ -241,11 +241,7 @@ impl Function { attrs: Vec::new(), lit: syn::Lit::Str(match &attrs.path { Path::Protocol(protocol) => { - break 'out syn::Expr::Path(syn::ExprPath { - attrs: Vec::new(), - qself: None, - path: protocol.clone(), - }) + break 'out syn::parse_quote!(&#protocol); } Path::None => name_string.clone(), Path::Rename(last) => { @@ -258,11 +254,7 @@ impl Function { match &attrs.path { Path::None => expr_lit(&self.sig.ident), Path::Rename(last) => expr_lit(&last.ident), - Path::Protocol(protocol) => syn::Expr::Path(syn::ExprPath { - attrs: Vec::new(), - qself: None, - path: protocol.clone(), - }), + Path::Protocol(protocol) => syn::parse_quote!(&#protocol), } }; diff --git a/crates/rune/src/compile/context.rs b/crates/rune/src/compile/context.rs index afd0a6d8e..f18029acb 100644 --- a/crates/rune/src/compile/context.rs +++ b/crates/rune/src/compile/context.rs @@ -68,7 +68,10 @@ impl TraitContext<'_> { /// Find the given protocol function for the current type. /// /// This requires that the function is defined. - pub fn find(&mut self, protocol: Protocol) -> Result, ContextError> { + pub fn find( + &mut self, + protocol: &'static Protocol, + ) -> Result, ContextError> { let name = protocol.to_instance()?; let hash = name @@ -115,7 +118,7 @@ impl TraitContext<'_> { /// Find or define a protocol function. pub fn find_or_define( &mut self, - protocol: Protocol, + protocol: &'static Protocol, function: F, ) -> Result, ContextError> where @@ -1004,7 +1007,7 @@ impl Context { } self.constants.try_insert( - Hash::associated_function(ty.hash, Protocol::INTO_TYPE_NAME), + Hash::associated_function(ty.hash, &Protocol::INTO_TYPE_NAME), ConstValue::from(ty.item.try_to_string()?), )?; @@ -1030,7 +1033,7 @@ impl Context { } rune::module::ModuleItemKind::Function(f) => { self.constants.try_insert( - Hash::associated_function(m.hash, Protocol::INTO_TYPE_NAME), + Hash::associated_function(m.hash, &Protocol::INTO_TYPE_NAME), ConstValue::from(m.item.try_to_string()?), )?; @@ -1120,7 +1123,7 @@ impl Context { if let Some((hash, item)) = &item { self.constants.try_insert( - Hash::associated_function(*hash, Protocol::INTO_TYPE_NAME), + Hash::associated_function(*hash, &Protocol::INTO_TYPE_NAME), ConstValue::from(item.try_to_string()?), )?; diff --git a/crates/rune/src/compile/meta.rs b/crates/rune/src/compile/meta.rs index 719a2e665..29d6d35eb 100644 --- a/crates/rune/src/compile/meta.rs +++ b/crates/rune/src/compile/meta.rs @@ -517,11 +517,11 @@ impl DocType { #[non_exhaustive] pub enum AssociatedKind { /// A protocol function implemented on the type itself. - Protocol(Protocol), + Protocol(&'static Protocol), /// A field function with the given protocol. - FieldFn(Protocol, Cow<'static, str>), + FieldFn(&'static Protocol, Cow<'static, str>), /// An index function with the given protocol. - IndexFn(Protocol, usize), + IndexFn(&'static Protocol, usize), /// The instance function refers to the given named instance fn. Instance(Cow<'static, str>), } @@ -532,10 +532,10 @@ impl AssociatedKind { match self { Self::Protocol(protocol) => Hash::associated_function(instance_type, protocol.hash), Self::IndexFn(protocol, index) => { - Hash::index_function(*protocol, instance_type, Hash::index(*index)) + Hash::index_function(protocol.hash, instance_type, Hash::index(*index)) } Self::FieldFn(protocol, field) => { - Hash::field_function(*protocol, instance_type, field.as_ref()) + Hash::field_function(protocol.hash, instance_type, field.as_ref()) } Self::Instance(name) => Hash::associated_function(instance_type, name.as_ref()), } diff --git a/crates/rune/src/compile/unit_builder.rs b/crates/rune/src/compile/unit_builder.rs index fd29aded9..f686e74fe 100644 --- a/crates/rune/src/compile/unit_builder.rs +++ b/crates/rune/src/compile/unit_builder.rs @@ -335,7 +335,7 @@ impl UnitBuilder { self.constants .try_insert( - Hash::associated_function(hash, Protocol::INTO_TYPE_NAME), + Hash::associated_function(hash, &Protocol::INTO_TYPE_NAME), ConstValue::from(rtti.item.try_to_string()?), ) .with_span(span)?; @@ -394,7 +394,7 @@ impl UnitBuilder { self.constants .try_insert( - Hash::associated_function(meta.hash, Protocol::INTO_TYPE_NAME), + Hash::associated_function(meta.hash, &Protocol::INTO_TYPE_NAME), ConstValue::from(signature.path.try_to_string()?), ) .with_span(span)?; @@ -453,7 +453,7 @@ impl UnitBuilder { self.constants .try_insert( - Hash::associated_function(meta.hash, Protocol::INTO_TYPE_NAME), + Hash::associated_function(meta.hash, &Protocol::INTO_TYPE_NAME), ConstValue::from(signature.path.try_to_string()?), ) .with_span(span)?; @@ -478,7 +478,7 @@ impl UnitBuilder { self.constants .try_insert( - Hash::associated_function(hash, Protocol::INTO_TYPE_NAME), + Hash::associated_function(hash, &Protocol::INTO_TYPE_NAME), ConstValue::from(rtti.item.try_to_string()?), ) .with_span(span)?; @@ -620,7 +620,7 @@ impl UnitBuilder { self.constants .try_insert( - Hash::associated_function(meta.hash, Protocol::INTO_TYPE_NAME), + Hash::associated_function(meta.hash, &Protocol::INTO_TYPE_NAME), ConstValue::from(name), ) .with_span(span)?; @@ -745,7 +745,7 @@ impl UnitBuilder { self.constants .try_insert( - Hash::associated_function(hash, Protocol::INTO_TYPE_NAME), + Hash::associated_function(hash, &Protocol::INTO_TYPE_NAME), ConstValue::from(signature.path.try_to_string().with_span(location.span)?), ) .with_span(location.span)?; diff --git a/crates/rune/src/compile/v1/assemble.rs b/crates/rune/src/compile/v1/assemble.rs index 658a47857..8fedbeb56 100644 --- a/crates/rune/src/compile/v1/assemble.rs +++ b/crates/rune/src/compile/v1/assemble.rs @@ -12,8 +12,9 @@ use crate::compile::{self, Assembly, ErrorKind, ItemId, ModId, Options, WithSpan use crate::hir; use crate::query::{ConstFn, Query, Used}; use crate::runtime::{ - ConstValue, ConstValueKind, Inline, Inst, InstAddress, InstAssignOp, InstOp, InstRange, - InstTarget, InstValue, InstVariant, Label, Output, PanicReason, Protocol, TypeCheck, + ConstValue, ConstValueKind, Inline, Inst, InstAddress, InstArithmeticOp, InstBitwiseOp, InstOp, + InstRange, InstShiftOp, InstTarget, InstValue, InstVariant, Label, Output, PanicReason, + Protocol, TypeCheck, }; use crate::shared::FixedVec; use crate::{Hash, SourceId}; @@ -1575,35 +1576,18 @@ fn compile_assign_binop<'a, 'hir>( span: &'hir dyn Spanned, needs: &mut dyn Needs<'a, 'hir>, ) -> compile::Result> { - let op = match bin_op { - ast::BinOp::AddAssign(..) => InstAssignOp::Add, - ast::BinOp::SubAssign(..) => InstAssignOp::Sub, - ast::BinOp::MulAssign(..) => InstAssignOp::Mul, - ast::BinOp::DivAssign(..) => InstAssignOp::Div, - ast::BinOp::RemAssign(..) => InstAssignOp::Rem, - ast::BinOp::BitAndAssign(..) => InstAssignOp::BitAnd, - ast::BinOp::BitXorAssign(..) => InstAssignOp::BitXor, - ast::BinOp::BitOrAssign(..) => InstAssignOp::BitOr, - ast::BinOp::ShlAssign(..) => InstAssignOp::Shl, - ast::BinOp::ShrAssign(..) => InstAssignOp::Shr, - _ => { - return Err(compile::Error::new(span, ErrorKind::UnsupportedBinaryExpr)); - } - }; - - let inst = match lhs.kind { + let (target, value) = match lhs.kind { // hir::ExprKind::Variable(name) => { let var = cx.scopes.get(&mut cx.q, lhs, name)?; let mut value = cx.scopes.defer(rhs); converge!(expr(cx, rhs, &mut value)?, free(value)); + let value = value.into_addr()?; - Inst::Assign { - op, - target: InstTarget::Address(var.addr), - value: value.addr()?.addr(), - } + let inst_target = InstTarget::Address(var.addr); + + (inst_target, value) } // . hir::ExprKind::FieldAccess(field_access) => { @@ -1616,20 +1600,11 @@ fn compile_assign_binop<'a, 'hir>( let value = value.into_addr()?; // field assignment - let inst = match field_access.expr_field { - hir::ExprField::Index(index) => Inst::Assign { - op, - target: InstTarget::TupleField(target.addr(), index), - value: value.addr(), - }, + let inst_target = match field_access.expr_field { + hir::ExprField::Index(index) => InstTarget::TupleField(target.addr(), index), hir::ExprField::Ident(ident) => { let slot = cx.q.unit.new_static_string(&field_access.expr, ident)?; - - Inst::Assign { - op, - target: InstTarget::Field(target.addr(), slot), - value: value.addr(), - } + InstTarget::Field(target.addr(), slot) } _ => { return Err(compile::Error::new(span, ErrorKind::BadFieldAccess)); @@ -1637,9 +1612,64 @@ fn compile_assign_binop<'a, 'hir>( }; target.free()?; - value.free()?; - inst + (inst_target, value) + } + _ => { + return Err(compile::Error::new(span, ErrorKind::UnsupportedBinaryExpr)); } + }; + + let inst = match bin_op { + ast::BinOp::AddAssign(..) => Inst::AssignArithmetic { + op: InstArithmeticOp::Add, + target, + value: value.addr(), + }, + ast::BinOp::SubAssign(..) => Inst::AssignArithmetic { + op: InstArithmeticOp::Sub, + target, + value: value.addr(), + }, + ast::BinOp::MulAssign(..) => Inst::AssignArithmetic { + op: InstArithmeticOp::Mul, + target, + value: value.addr(), + }, + ast::BinOp::DivAssign(..) => Inst::AssignArithmetic { + op: InstArithmeticOp::Div, + target, + value: value.addr(), + }, + ast::BinOp::RemAssign(..) => Inst::AssignArithmetic { + op: InstArithmeticOp::Rem, + target, + value: value.addr(), + }, + ast::BinOp::BitAndAssign(..) => Inst::AssignBitwise { + op: InstBitwiseOp::BitAnd, + target, + value: value.addr(), + }, + ast::BinOp::BitXorAssign(..) => Inst::AssignBitwise { + op: InstBitwiseOp::BitXor, + target, + value: value.addr(), + }, + ast::BinOp::BitOrAssign(..) => Inst::AssignBitwise { + op: InstBitwiseOp::BitOr, + target, + value: value.addr(), + }, + ast::BinOp::ShlAssign(..) => Inst::AssignShift { + op: InstShiftOp::Shl, + target, + value: value.addr(), + }, + ast::BinOp::ShrAssign(..) => Inst::AssignShift { + op: InstShiftOp::Shr, + target, + value: value.addr(), + }, _ => { return Err(compile::Error::new(span, ErrorKind::UnsupportedBinaryExpr)); } @@ -1651,6 +1681,7 @@ fn compile_assign_binop<'a, 'hir>( cx.asm.push(Inst::unit(out), span)?; } + value.free()?; Ok(Asm::new(span, ())) } @@ -2128,7 +2159,7 @@ fn expr_for<'a, 'hir>( cx.asm.push_with_comment( Inst::CallAssociated { addr: into_iter.addr(), - hash: *Protocol::INTO_ITER, + hash: Protocol::INTO_ITER.hash, args: 1, out: into_iter.output(), }, @@ -2143,7 +2174,7 @@ fn expr_for<'a, 'hir>( cx.asm.push_with_comment( Inst::LoadInstanceFn { addr: into_iter.addr(), - hash: *Protocol::NEXT, + hash: Protocol::NEXT.hash, out: offset.output(), }, &hir.iter, @@ -2190,7 +2221,7 @@ fn expr_for<'a, 'hir>( cx.asm.push_with_comment( Inst::CallAssociated { addr: into_iter_copy.addr(), - hash: *Protocol::NEXT, + hash: Protocol::NEXT.hash, args: 1, out: binding.output(), }, diff --git a/crates/rune/src/doc/artifacts.rs b/crates/rune/src/doc/artifacts.rs index 00b526994..ef23ac745 100644 --- a/crates/rune/src/doc/artifacts.rs +++ b/crates/rune/src/doc/artifacts.rs @@ -35,7 +35,7 @@ pub(crate) enum TestKind { #[default] Free, /// The test originates from a protocol function. - Protocol(Protocol), + Protocol(&'static Protocol), } /// A discovered test. diff --git a/crates/rune/src/doc/context.rs b/crates/rune/src/doc/context.rs index 66ba6e342..4f8508ab9 100644 --- a/crates/rune/src/doc/context.rs +++ b/crates/rune/src/doc/context.rs @@ -47,11 +47,11 @@ pub(crate) struct Function<'a> { #[derive(Debug)] pub(crate) enum AssocFnKind<'a> { /// A protocol function implemented on the type itself. - Protocol(Protocol), + Protocol(&'static Protocol), /// A field function with the given protocol. - FieldFn(Protocol, &'a str), + FieldFn(&'static Protocol, &'a str), /// An index function with the given protocol. - IndexFn(Protocol, usize), + IndexFn(&'static Protocol, usize), /// The instance function refers to the given named instance fn. Method(&'a Item, &'a str, Signature), } diff --git a/crates/rune/src/function_meta.rs b/crates/rune/src/function_meta.rs index 31c175efa..e66020355 100644 --- a/crates/rune/src/function_meta.rs +++ b/crates/rune/src/function_meta.rs @@ -22,7 +22,7 @@ mod sealed { pub trait Sealed {} impl Sealed for &str {} - impl Sealed for Protocol {} + impl Sealed for &Protocol {} impl Sealed for Params {} } @@ -170,7 +170,7 @@ pub struct AssociatedName { } impl AssociatedName { - pub(crate) fn index(protocol: Protocol, index: usize) -> Self { + pub(crate) fn index(protocol: &'static Protocol, index: usize) -> Self { Self { kind: meta::AssociatedKind::IndexFn(protocol, index), function_parameters: Hash::EMPTY, @@ -190,7 +190,7 @@ pub trait ToInstance: self::sealed::Sealed { /// Trait used to determine what can be used as an instance function name. pub trait ToFieldFunction: self::sealed::Sealed { #[doc(hidden)] - fn to_field_function(self, protocol: Protocol) -> alloc::Result; + fn to_field_function(self, protocol: &'static Protocol) -> alloc::Result; } impl ToInstance for &'static str { @@ -207,7 +207,7 @@ impl ToInstance for &'static str { impl ToFieldFunction for &'static str { #[inline] - fn to_field_function(self, protocol: Protocol) -> alloc::Result { + fn to_field_function(self, protocol: &'static Protocol) -> alloc::Result { Ok(AssociatedName { kind: meta::AssociatedKind::FieldFn(protocol, Cow::Borrowed(self)), function_parameters: Hash::EMPTY, diff --git a/crates/rune/src/module/module.rs b/crates/rune/src/module/module.rs index 75cc4e9ed..2c8ad7dd5 100644 --- a/crates/rune/src/module/module.rs +++ b/crates/rune/src/module/module.rs @@ -1139,7 +1139,7 @@ impl Module { /// associate more metadata with the inserted item. pub fn field_function( &mut self, - protocol: Protocol, + protocol: &'static Protocol, name: N, f: F, ) -> Result, ContextError> @@ -1161,7 +1161,7 @@ impl Module { #[inline] pub fn field_fn( &mut self, - protocol: Protocol, + protocol: &'static Protocol, name: N, f: F, ) -> Result, ContextError> @@ -1180,7 +1180,7 @@ impl Module { /// enum as configured with [Module::enum_meta]. pub fn index_function( &mut self, - protocol: Protocol, + protocol: &'static Protocol, index: usize, f: F, ) -> Result, ContextError> @@ -1202,7 +1202,7 @@ impl Module { #[inline] pub fn index_fn( &mut self, - protocol: Protocol, + protocol: &'static Protocol, index: usize, f: F, ) -> Result, ContextError> diff --git a/crates/rune/src/modules/clone.rs b/crates/rune/src/modules/clone.rs index a996b5880..b37a92410 100644 --- a/crates/rune/src/modules/clone.rs +++ b/crates/rune/src/modules/clone.rs @@ -31,7 +31,7 @@ pub fn module() -> Result { })?; t.handler(|cx| { - _ = cx.find(Protocol::CLONE)?; + _ = cx.find(&Protocol::CLONE)?; Ok(()) })?; diff --git a/crates/rune/src/modules/cmp.rs b/crates/rune/src/modules/cmp.rs index 74a6ad472..fc3058a36 100644 --- a/crates/rune/src/modules/cmp.rs +++ b/crates/rune/src/modules/cmp.rs @@ -57,14 +57,15 @@ pub fn module() -> Result { /// "An ordering where a compared value is greater than another. })?; - m.associated_function(Protocol::IS_VARIANT, |this: Ordering, index: usize| match ( - this, index, - ) { - (Ordering::Less, 0) => true, - (Ordering::Equal, 1) => true, - (Ordering::Greater, 2) => true, - _ => false, - })?; + m.associated_function( + &Protocol::IS_VARIANT, + |this: Ordering, index: usize| match (this, index) { + (Ordering::Less, 0) => true, + (Ordering::Equal, 1) => true, + (Ordering::Greater, 2) => true, + _ => false, + }, + )?; } m.function_meta(ordering_partial_eq__meta)?; @@ -178,7 +179,7 @@ pub fn module() -> Result { })?; t.handler(|cx| { - let partial_eq = cx.find(Protocol::PARTIAL_EQ)?; + let partial_eq = cx.find(&Protocol::PARTIAL_EQ)?; let partial_eq = Caller::<(Value, Value), 2, bool>::new(partial_eq); cx.function("ne", move |a: Value, b: Value| { @@ -250,7 +251,7 @@ pub fn module() -> Result { })?; t.handler(|cx| { - _ = cx.find(Protocol::EQ)?; + _ = cx.find(&Protocol::EQ)?; Ok(()) })?; @@ -399,10 +400,10 @@ pub fn module() -> Result { })?; t.handler(|cx| { - let partial_cmp = cx.find(Protocol::PARTIAL_CMP)?; + let partial_cmp = cx.find(&Protocol::PARTIAL_CMP)?; let partial_cmp = Caller::<(Value, Value), 2, Option>::new(partial_cmp); - cx.find_or_define(Protocol::LT, { + cx.find_or_define(&Protocol::LT, { let partial_cmp = partial_cmp.clone(); move |a: Value, b: Value| { @@ -414,7 +415,7 @@ pub fn module() -> Result { } })?; - cx.find_or_define(Protocol::LE, { + cx.find_or_define(&Protocol::LE, { let partial_cmp = partial_cmp.clone(); move |a: Value, b: Value| { @@ -426,7 +427,7 @@ pub fn module() -> Result { } })?; - cx.find_or_define(Protocol::GT, { + cx.find_or_define(&Protocol::GT, { let partial_cmp = partial_cmp.clone(); move |a: Value, b: Value| { @@ -438,7 +439,7 @@ pub fn module() -> Result { } })?; - cx.find_or_define(Protocol::GE, { + cx.find_or_define(&Protocol::GE, { let partial_cmp = partial_cmp.clone(); move |a: Value, b: Value| { @@ -601,10 +602,10 @@ pub fn module() -> Result { })?; t.handler(|cx| { - let cmp = cx.find(Protocol::CMP)?; + let cmp = cx.find(&Protocol::CMP)?; let cmp = Caller::<(Value, Value), 2, Ordering>::new(cmp); - cx.find_or_define(Protocol::MIN, { + cx.find_or_define(&Protocol::MIN, { let cmp = cmp.clone(); move |a: Value, b: Value| match vm_try!(cmp.call((a.clone(), b.clone()))) { @@ -613,7 +614,7 @@ pub fn module() -> Result { } })?; - cx.find_or_define(Protocol::MAX, { + cx.find_or_define(&Protocol::MAX, { let cmp = cmp.clone(); move |a: Value, b: Value| match vm_try!(cmp.call((a.clone(), b.clone()))) { diff --git a/crates/rune/src/modules/collections/vec_deque.rs b/crates/rune/src/modules/collections/vec_deque.rs index 71f317d2d..7a1ff37ec 100644 --- a/crates/rune/src/modules/collections/vec_deque.rs +++ b/crates/rune/src/modules/collections/vec_deque.rs @@ -40,8 +40,8 @@ pub fn module() -> Result { m.function_meta(VecDeque::rotate_left)?; m.function_meta(VecDeque::rotate_right)?; - m.associated_function(Protocol::INDEX_GET, VecDeque::get)?; - m.associated_function(Protocol::INDEX_SET, VecDeque::set)?; + m.associated_function(&Protocol::INDEX_GET, VecDeque::get)?; + m.associated_function(&Protocol::INDEX_SET, VecDeque::set)?; m.function_meta(VecDeque::debug_fmt)?; diff --git a/crates/rune/src/modules/iter.rs b/crates/rune/src/modules/iter.rs index 0425c959a..cd1dac14f 100644 --- a/crates/rune/src/modules/iter.rs +++ b/crates/rune/src/modules/iter.rs @@ -155,7 +155,7 @@ pub fn module() -> Result { })?; t.handler(|cx| { - _ = cx.find(Protocol::LEN)?; + _ = cx.find(&Protocol::LEN)?; Ok(()) })?; @@ -202,15 +202,15 @@ pub fn module() -> Result { })?; t.handler(|cx| { - let next = cx.find(Protocol::NEXT)?; + let next = cx.find(&Protocol::NEXT)?; let next = Caller::<(Value,), 1, Option>::new(next); let size_hint = - cx.find_or_define(Protocol::SIZE_HINT, |_: Value| (0usize, None::))?; + cx.find_or_define(&Protocol::SIZE_HINT, |_: Value| (0usize, None::))?; let size_hint = Caller::<(&Value,), 1, (usize, Option)>::new(size_hint); - cx.find_or_define(Protocol::NTH, { + cx.find_or_define(&Protocol::NTH, { let next = next.clone(); move |iter: Value, mut n: usize| loop { @@ -226,7 +226,7 @@ pub fn module() -> Result { } })?; - cx.function(Protocol::INTO_ITER, |value: Value| value)?; + cx.function(&Protocol::INTO_ITER, |value: Value| value)?; cx.function("into_iter", |value: Value| value)?; @@ -1630,9 +1630,9 @@ pub fn module() -> Result { })?; t.handler(|cx| { - let next_back = cx.find(Protocol::NEXT_BACK)?; + let next_back = cx.find(&Protocol::NEXT_BACK)?; - cx.find_or_define(Protocol::NTH_BACK, { + cx.find_or_define(&Protocol::NTH_BACK, { let next_back = next_back.clone(); move |iterator: Value, mut n: usize| loop { diff --git a/crates/rune/src/modules/object.rs b/crates/rune/src/modules/object.rs index b06b58cc9..d12e52514 100644 --- a/crates/rune/src/modules/object.rs +++ b/crates/rune/src/modules/object.rs @@ -63,7 +63,7 @@ pub fn module() -> Result { m.function_meta(Object::rune_iter__meta)?; m.function_meta(Object::rune_keys__meta)?; m.function_meta(Object::rune_values__meta)?; - m.associated_function(Protocol::INTO_ITER, Object::rune_iter)?; + m.associated_function(&Protocol::INTO_ITER, Object::rune_iter)?; m.ty::()?; m.function_meta(RuneIter::next__meta)?; diff --git a/crates/rune/src/modules/option.rs b/crates/rune/src/modules/option.rs index 9868903eb..8c016417c 100644 --- a/crates/rune/src/modules/option.rs +++ b/crates/rune/src/modules/option.rs @@ -34,7 +34,7 @@ pub fn module() -> Result { .static_docs(&["The empty value."])?; m.associated_function( - Protocol::IS_VARIANT, + &Protocol::IS_VARIANT, |this: &Option, index: usize| match (this, index) { (Option::Some(_), 0) => true, (Option::None, 1) => true, @@ -42,7 +42,7 @@ pub fn module() -> Result { }, )?; - m.index_function(Protocol::GET, 0, |this: &Option| match this { + m.index_function(&Protocol::GET, 0, |this: &Option| match this { Option::Some(value) => VmResult::Ok(value.clone()), _ => VmResult::err(RuntimeError::__rune_macros__unsupported_tuple_index_get( as Any>::ANY_TYPE_INFO, diff --git a/crates/rune/src/modules/result.rs b/crates/rune/src/modules/result.rs index 984ef772f..3485a3947 100644 --- a/crates/rune/src/modules/result.rs +++ b/crates/rune/src/modules/result.rs @@ -37,7 +37,7 @@ pub fn module() -> Result { .static_docs(&["Contains the error value"])?; m.associated_function( - Protocol::IS_VARIANT, + &Protocol::IS_VARIANT, |this: &Result, index: usize| match (this, index) { (Result::Ok(_), 0) => true, (Result::Err(_), 1) => true, @@ -45,10 +45,14 @@ pub fn module() -> Result { }, )?; - m.index_function(Protocol::GET, 0, |this: &Result| match this { - Result::Ok(value) => VmResult::Ok(value.clone()), - Result::Err(value) => VmResult::Ok(value.clone()), - })?; + m.index_function( + &Protocol::GET, + 0, + |this: &Result| match this { + Result::Ok(value) => VmResult::Ok(value.clone()), + Result::Err(value) => VmResult::Ok(value.clone()), + }, + )?; m.function_meta(ok)?; m.function_meta(is_ok)?; diff --git a/crates/rune/src/params.rs b/crates/rune/src/params.rs index fcdb8d175..dba7cdd28 100644 --- a/crates/rune/src/params.rs +++ b/crates/rune/src/params.rs @@ -30,7 +30,7 @@ where T: ToFieldFunction, { #[inline] - fn to_field_function(self, protocol: Protocol) -> alloc::Result { + fn to_field_function(self, protocol: &'static Protocol) -> alloc::Result { let info = self.name.to_field_function(protocol)?; Ok(AssociatedName { diff --git a/crates/rune/src/runtime/inst.rs b/crates/rune/src/runtime/inst.rs index 706ac70e7..c25faf89c 100644 --- a/crates/rune/src/runtime/inst.rs +++ b/crates/rune/src/runtime/inst.rs @@ -999,7 +999,7 @@ pub enum Inst { /// ``` #[musli(packed)] Op { - /// The actual operation. + /// The kind of operation. op: InstOp, /// The address of the first argument. a: InstAddress, @@ -1008,11 +1008,31 @@ pub enum Inst { /// Whether the produced value from the operation should be kept or not. out: Output, }, - /// A built-in operation that assigns to the left-hand side operand. + /// Instruction for assigned arithmetic operations. #[musli(packed)] - Assign { - /// The actual operation. - op: InstAssignOp, + AssignArithmetic { + /// The kind of operation. + op: InstArithmeticOp, + /// The target of the operation. + target: InstTarget, + /// The value being assigned. + value: InstAddress, + }, + /// Instruction for assigned bitwise operations. + #[musli(packed)] + AssignBitwise { + /// The kind of operation. + op: InstBitwiseOp, + /// The target of the operation. + target: InstTarget, + /// The value being assigned. + value: InstAddress, + }, + /// Instruction for assigned shift operations. + #[musli(packed)] + AssignShift { + /// The kind of operation. + op: InstShiftOp, /// The target of the operation. target: InstTarget, /// The value being assigned. @@ -1375,7 +1395,7 @@ impl fmt::Display for InstTarget { /// An operation between two values on the machine. #[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] #[try_clone(copy)] -pub enum InstAssignOp { +pub enum InstArithmeticOp { /// The add operation. `a + b`. Add, /// The sub operation. `a - b`. @@ -1386,19 +1406,10 @@ pub enum InstAssignOp { Div, /// The remainder operation. `a % b`. Rem, - /// The bitwise and operation. `a & b`. - BitAnd, - /// The bitwise xor operation. `a ^ b`. - BitXor, - /// The bitwise or operation. `a | b`. - BitOr, - /// The shift left operation. `a << b`. - Shl, - /// The shift right operation. `a << b`. - Shr, } -impl fmt::Display for InstAssignOp { +impl fmt::Display for InstArithmeticOp { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Add => { @@ -1416,6 +1427,28 @@ impl fmt::Display for InstAssignOp { Self::Rem => { write!(f, "%")?; } + } + + Ok(()) + } +} + +/// An operation between two values on the machine. +#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] +pub enum InstBitwiseOp { + /// The bitwise and operation. `a & b`. + BitAnd, + /// The bitwise xor operation. `a ^ b`. + BitXor, + /// The bitwise or operation. `a | b`. + BitOr, +} + +impl fmt::Display for InstBitwiseOp { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { Self::BitAnd => { write!(f, "&")?; } @@ -1425,6 +1458,26 @@ impl fmt::Display for InstAssignOp { Self::BitOr => { write!(f, "|")?; } + } + + Ok(()) + } +} + +/// An operation between two values on the machine. +#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] +pub enum InstShiftOp { + /// The shift left operation. `a << b`. + Shl, + /// The shift right operation. `a << b`. + Shr, +} + +impl fmt::Display for InstShiftOp { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { Self::Shl => { write!(f, "<<")?; } diff --git a/crates/rune/src/runtime/mod.rs b/crates/rune/src/runtime/mod.rs index 2835d5431..e31e07e51 100644 --- a/crates/rune/src/runtime/mod.rs +++ b/crates/rune/src/runtime/mod.rs @@ -79,8 +79,8 @@ pub use self::guarded_args::GuardedArgs; mod inst; pub use self::inst::{ - Inst, InstAddress, InstAssignOp, InstOp, InstRange, InstTarget, InstValue, InstVariant, - IntoOutput, Output, PanicReason, TypeCheck, + Inst, InstAddress, InstArithmeticOp, InstBitwiseOp, InstOp, InstRange, InstShiftOp, InstTarget, + InstValue, InstVariant, IntoOutput, Output, PanicReason, TypeCheck, }; mod iterator; diff --git a/crates/rune/src/runtime/protocol.rs b/crates/rune/src/runtime/protocol.rs index fb0dcea95..4bf2cfb60 100644 --- a/crates/rune/src/runtime/protocol.rs +++ b/crates/rune/src/runtime/protocol.rs @@ -8,7 +8,7 @@ use crate::Hash; #[doc(inline)] pub use rune_core::protocol::Protocol; -impl ToInstance for Protocol { +impl ToInstance for &'static Protocol { #[inline] fn to_instance(self) -> alloc::Result { Ok(AssociatedName { diff --git a/crates/rune/src/runtime/protocol_caller.rs b/crates/rune/src/runtime/protocol_caller.rs index baf4740dd..617d4df8a 100644 --- a/crates/rune/src/runtime/protocol_caller.rs +++ b/crates/rune/src/runtime/protocol_caller.rs @@ -9,7 +9,7 @@ pub(crate) trait ProtocolCaller: 'static { /// Call the given protocol function. fn call_protocol_fn( &mut self, - protocol: Protocol, + protocol: &'static Protocol, target: Value, args: &mut dyn DynArgs, ) -> VmResult { @@ -27,7 +27,7 @@ pub(crate) trait ProtocolCaller: 'static { /// Call the given protocol function. fn try_call_protocol_fn( &mut self, - protocol: Protocol, + protocol: &'static Protocol, target: Value, args: &mut dyn DynArgs, ) -> VmResult>; @@ -41,7 +41,7 @@ pub(crate) struct EnvProtocolCaller; impl ProtocolCaller for EnvProtocolCaller { fn try_call_protocol_fn( &mut self, - protocol: Protocol, + protocol: &Protocol, target: Value, args: &mut dyn DynArgs, ) -> VmResult> { @@ -96,7 +96,7 @@ impl ProtocolCaller for EnvProtocolCaller { impl ProtocolCaller for Vm { fn try_call_protocol_fn( &mut self, - protocol: Protocol, + protocol: &'static Protocol, target: Value, args: &mut dyn DynArgs, ) -> VmResult> { diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index b7a9de9c8..8f16b2157 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -347,7 +347,7 @@ impl Value { let mut args = DynGuardedArgs::new((f,)); let result = - vm_try!(caller.call_protocol_fn(Protocol::DISPLAY_FMT, self.clone(), &mut args)); + vm_try!(caller.call_protocol_fn(&Protocol::DISPLAY_FMT, self.clone(), &mut args)); VmResult::Ok(vm_try!(<()>::from_value(result))) } @@ -387,7 +387,7 @@ impl Value { } VmResult::Ok(vm_try!(caller.call_protocol_fn( - Protocol::CLONE, + &Protocol::CLONE, self.clone(), &mut () ))) @@ -427,7 +427,7 @@ impl Value { let mut args = DynGuardedArgs::new((&mut *f,)); match vm_try!(caller.try_call_protocol_fn( - Protocol::DEBUG_FMT, + &Protocol::DEBUG_FMT, self.clone(), &mut args )) { @@ -470,7 +470,7 @@ impl Value { } pub(crate) fn into_iter_with(self, caller: &mut dyn ProtocolCaller) -> VmResult { - let value = vm_try!(caller.call_protocol_fn(Protocol::INTO_ITER, self, &mut ())); + let value = vm_try!(caller.call_protocol_fn(&Protocol::INTO_ITER, self, &mut ())); VmResult::Ok(Iterator::new(value)) } @@ -489,7 +489,7 @@ impl Value { /// /// [`Vm`]: crate::Vm pub fn into_type_name(self) -> VmResult { - let hash = Hash::associated_function(self.type_hash(), Protocol::INTO_TYPE_NAME); + let hash = Hash::associated_function(self.type_hash(), &Protocol::INTO_TYPE_NAME); crate::runtime::env::shared(|context, unit| { if let Some(name) = context.constant(&hash) { @@ -808,7 +808,7 @@ impl Value { }; let value = EnvProtocolCaller - .call_protocol_fn(Protocol::INTO_FUTURE, target, &mut ()) + .call_protocol_fn(&Protocol::INTO_FUTURE, target, &mut ()) .into_result()?; Future::from_value(value) @@ -1067,7 +1067,7 @@ impl Value { self.bin_op_with( b, caller, - Protocol::PARTIAL_EQ, + &Protocol::PARTIAL_EQ, Inline::partial_eq, |lhs, rhs, caller| { if lhs.0.variant_hash != rhs.0.variant_hash { @@ -1098,7 +1098,7 @@ impl Value { /// This is the basis for the eq operation (`==`). #[cfg_attr(feature = "bench", inline(never))] pub(crate) fn eq_with(&self, b: &Value, caller: &mut dyn ProtocolCaller) -> VmResult { - self.bin_op_with(b, caller, Protocol::EQ, Inline::eq, |lhs, rhs, caller| { + self.bin_op_with(b, caller, &Protocol::EQ, Inline::eq, |lhs, rhs, caller| { if lhs.0.variant_hash != rhs.0.variant_hash { return VmResult::Ok(false); } @@ -1133,7 +1133,7 @@ impl Value { self.bin_op_with( b, caller, - Protocol::PARTIAL_CMP, + &Protocol::PARTIAL_CMP, Inline::partial_cmp, |lhs, rhs, caller| { let ord = lhs.0.variant_hash.cmp(&rhs.0.variant_hash); @@ -1170,15 +1170,21 @@ impl Value { b: &Value, caller: &mut dyn ProtocolCaller, ) -> VmResult { - self.bin_op_with(b, caller, Protocol::CMP, Inline::cmp, |lhs, rhs, caller| { - let ord = lhs.0.variant_hash.cmp(&rhs.0.variant_hash); + self.bin_op_with( + b, + caller, + &Protocol::CMP, + Inline::cmp, + |lhs, rhs, caller| { + let ord = lhs.0.variant_hash.cmp(&rhs.0.variant_hash); - if ord != Ordering::Equal { - return VmResult::Ok(ord); - } + if ord != Ordering::Equal { + return VmResult::Ok(ord); + } - Vec::cmp_with(lhs.1, rhs.1, caller) - }) + Vec::cmp_with(lhs.1, rhs.1, caller) + }, + ) } /// Hash the current value. @@ -1213,7 +1219,7 @@ impl Value { let mut args = DynGuardedArgs::new((hasher,)); if let CallResultOnly::Ok(value) = - vm_try!(caller.try_call_protocol_fn(Protocol::HASH, self.clone(), &mut args)) + vm_try!(caller.try_call_protocol_fn(&Protocol::HASH, self.clone(), &mut args)) { return VmResult::Ok(vm_try!(<_>::from_value(value))); } @@ -1228,7 +1234,7 @@ impl Value { &self, b: &Value, caller: &mut dyn ProtocolCaller, - protocol: Protocol, + protocol: &'static Protocol, inline: fn(&Inline, &Inline) -> Result, dynamic: fn( (&Arc, &[Value]), @@ -1395,26 +1401,29 @@ impl Value { } pub(crate) fn protocol_into_iter(&self) -> VmResult { - EnvProtocolCaller.call_protocol_fn(Protocol::INTO_ITER, self.clone(), &mut ()) + EnvProtocolCaller.call_protocol_fn(&Protocol::INTO_ITER, self.clone(), &mut ()) } pub(crate) fn protocol_next(&self) -> VmResult> { let value = - vm_try!(EnvProtocolCaller.call_protocol_fn(Protocol::NEXT, self.clone(), &mut ())); + vm_try!(EnvProtocolCaller.call_protocol_fn(&Protocol::NEXT, self.clone(), &mut ())); VmResult::Ok(vm_try!(FromValue::from_value(value))) } pub(crate) fn protocol_next_back(&self) -> VmResult> { - let value = - vm_try!(EnvProtocolCaller.call_protocol_fn(Protocol::NEXT_BACK, self.clone(), &mut ())); + let value = vm_try!(EnvProtocolCaller.call_protocol_fn( + &Protocol::NEXT_BACK, + self.clone(), + &mut () + )); VmResult::Ok(vm_try!(FromValue::from_value(value))) } pub(crate) fn protocol_nth_back(&self, n: usize) -> VmResult> { let value = vm_try!(EnvProtocolCaller.call_protocol_fn( - Protocol::NTH_BACK, + &Protocol::NTH_BACK, self.clone(), &mut Some((n,)) )); @@ -1424,14 +1433,17 @@ impl Value { pub(crate) fn protocol_len(&self) -> VmResult { let value = - vm_try!(EnvProtocolCaller.call_protocol_fn(Protocol::LEN, self.clone(), &mut ())); + vm_try!(EnvProtocolCaller.call_protocol_fn(&Protocol::LEN, self.clone(), &mut ())); VmResult::Ok(vm_try!(FromValue::from_value(value))) } pub(crate) fn protocol_size_hint(&self) -> VmResult<(usize, Option)> { - let value = - vm_try!(EnvProtocolCaller.call_protocol_fn(Protocol::SIZE_HINT, self.clone(), &mut ())); + let value = vm_try!(EnvProtocolCaller.call_protocol_fn( + &Protocol::SIZE_HINT, + self.clone(), + &mut () + )); VmResult::Ok(vm_try!(FromValue::from_value(value))) } diff --git a/crates/rune/src/runtime/vm.rs b/crates/rune/src/runtime/vm.rs index 51c92119f..b041a2f14 100644 --- a/crates/rune/src/runtime/vm.rs +++ b/crates/rune/src/runtime/vm.rs @@ -17,12 +17,13 @@ use crate::runtime; use super::{ budget, Args, Awaited, BorrowMut, Bytes, Call, ControlFlow, DynArgs, DynGuardedArgs, Dynamic, Format, FormatSpec, Formatter, FromValue, Function, Future, Generator, GeneratorState, - GuardedArgs, Inline, Inst, InstAddress, InstAssignOp, InstOp, InstRange, InstTarget, InstValue, - InstVariant, Object, Output, OwnedTuple, Pair, Panic, Protocol, ProtocolCaller, Range, - RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Repr, RttiKind, - RuntimeContext, Select, SelectFuture, Stack, Stream, Type, TypeCheck, TypeHash, TypeInfo, - TypeOf, Unit, UnitFn, UnitStorage, Value, Vec, VmDiagnostics, VmDiagnosticsObj, VmError, - VmErrorKind, VmExecution, VmHalt, VmIntegerRepr, VmResult, VmSendExecution, + GuardedArgs, Inline, Inst, InstAddress, InstArithmeticOp, InstBitwiseOp, InstOp, InstRange, + InstShiftOp, InstTarget, InstValue, InstVariant, Object, Output, OwnedTuple, Pair, Panic, + Protocol, ProtocolCaller, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, + RangeToInclusive, Repr, RttiKind, RuntimeContext, Select, SelectFuture, Stack, Stream, Type, + TypeCheck, TypeHash, TypeInfo, TypeOf, Unit, UnitFn, UnitStorage, Value, Vec, VmDiagnostics, + VmDiagnosticsObj, VmError, VmErrorKind, VmExecution, VmHalt, VmIntegerRepr, VmResult, + VmSendExecution, }; /// Helper to take a value, replacing the old one with empty. @@ -593,7 +594,7 @@ impl Vm { #[inline] fn call_field_fn( &mut self, - protocol: Protocol, + protocol: impl IntoHash, target: Value, name: impl IntoHash, args: &mut dyn DynArgs, @@ -608,7 +609,7 @@ impl Vm { #[inline] fn call_index_fn( &mut self, - protocol: Protocol, + protocol: impl IntoHash, target: Value, index: usize, args: &mut dyn DynArgs, @@ -1185,34 +1186,30 @@ impl Vm { fn internal_num_assign( &mut self, target: InstTarget, - protocol: Protocol, - error: fn() -> VmErrorKind, - signed_op: fn(i64, i64) -> Option, - unsigned_op: fn(u64, u64) -> Option, - float_op: fn(f64, f64) -> f64, + ops: &'static ArithmeticOps, rhs: InstAddress, ) -> VmResult<()> { let fallback = match vm_try!(target_value(&mut self.stack, &self.unit, target, rhs)) { TargetValue::Same(value) => { match value.as_mut() { Repr::Inline(Inline::Signed(value)) => { - let out = vm_try!(signed_op(*value, *value).ok_or_else(error)); + let out = vm_try!((ops.signed_op)(*value, *value).ok_or_else(ops.error)); *value = out; return VmResult::Ok(()); } Repr::Inline(Inline::Unsigned(value)) => { - let out = vm_try!(unsigned_op(*value, *value).ok_or_else(error)); + let out = vm_try!((ops.unsigned_op)(*value, *value).ok_or_else(ops.error)); *value = out; return VmResult::Ok(()); } Repr::Inline(Inline::Float(value)) => { - let out = float_op(*value, *value); + let out = (ops.float_op)(*value, *value); *value = out; return VmResult::Ok(()); } Repr::Inline(value) => { return err(VmErrorKind::UnsupportedBinaryOperation { - op: protocol.name, + op: ops.protocol.name, lhs: value.type_info(), rhs: value.type_info(), }); @@ -1227,24 +1224,24 @@ impl Vm { (Repr::Inline(lhs), Repr::Inline(rhs)) => match (lhs, rhs) { (Inline::Signed(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); - let out = vm_try!(signed_op(*lhs, rhs).ok_or_else(error)); + let out = vm_try!((ops.signed_op)(*lhs, rhs).ok_or_else(ops.error)); *lhs = out; return VmResult::Ok(()); } (Inline::Unsigned(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); - let out = vm_try!(unsigned_op(*lhs, rhs).ok_or_else(error)); + let out = vm_try!((ops.unsigned_op)(*lhs, rhs).ok_or_else(ops.error)); *lhs = out; return VmResult::Ok(()); } (Inline::Float(lhs), Inline::Float(rhs)) => { - let out = float_op(*lhs, *rhs); + let out = (ops.float_op)(*lhs, *rhs); *lhs = out; return VmResult::Ok(()); } (lhs, rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { - op: protocol.name, + op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), }); @@ -1252,7 +1249,7 @@ impl Vm { }, (Repr::Inline(lhs), rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { - op: protocol.name, + op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), }); @@ -1265,7 +1262,7 @@ impl Vm { TargetValue::Fallback(fallback) => fallback, }; - self.target_fallback_assign(fallback, protocol) + self.target_fallback_assign(fallback, ops.protocol) } /// Execute a fallback operation. @@ -1273,7 +1270,7 @@ impl Vm { fn target_fallback_assign( &mut self, fallback: TargetFallback, - protocol: Protocol, + protocol: &Protocol, ) -> VmResult<()> { match fallback { TargetFallback::Value(lhs, rhs) => { @@ -1282,7 +1279,7 @@ impl Vm { if let CallResult::Unsupported(lhs) = vm_try!(self.call_instance_fn( Isolated::None, lhs, - protocol, + protocol.hash, &mut args, Output::discard() )) { @@ -1316,7 +1313,7 @@ impl Vm { let mut args = DynGuardedArgs::new((rhs,)); if let CallResult::Unsupported(lhs) = vm_try!(self.call_index_fn( - protocol, + protocol.hash, lhs.clone(), index, &mut args, @@ -1337,7 +1334,7 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn internal_num( &mut self, - protocol: Protocol, + protocol: &Protocol, error: fn() -> VmErrorKind, signed_op: fn(i64, i64) -> Option, unsigned_op: fn(u64, u64) -> Option, @@ -1407,7 +1404,7 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn internal_bit( &mut self, - protocol: Protocol, + protocol: &Protocol, signed_op: fn(i64, i64) -> i64, unsigned_op: fn(u64, u64) -> u64, bool_op: fn(bool, bool) -> bool, @@ -1475,10 +1472,7 @@ impl Vm { fn internal_infallible_bitwise_assign( &mut self, target: InstTarget, - protocol: Protocol, - signed_op: fn(&mut i64, i64), - unsigned_op: fn(&mut u64, u64), - bool_op: fn(&mut bool, bool), + ops: &'static BitwiseOps, rhs: InstAddress, ) -> VmResult<()> { let fallback = match vm_try!(target_value(&mut self.stack, &self.unit, target, rhs)) { @@ -1486,22 +1480,22 @@ impl Vm { match value.as_mut() { Repr::Inline(Inline::Unsigned(value)) => { let rhs = *value; - unsigned_op(value, rhs); + (ops.unsigned_op)(value, rhs); return VmResult::Ok(()); } Repr::Inline(Inline::Signed(value)) => { let rhs = *value; - signed_op(value, rhs); + (ops.signed_op)(value, rhs); return VmResult::Ok(()); } Repr::Inline(Inline::Bool(value)) => { let rhs = *value; - bool_op(value, rhs); + (ops.bool_op)(value, rhs); return VmResult::Ok(()); } Repr::Inline(value) => { return err(VmErrorKind::UnsupportedBinaryOperation { - op: protocol.name, + op: ops.protocol.name, lhs: value.type_info(), rhs: value.type_info(), }); @@ -1516,21 +1510,21 @@ impl Vm { (Repr::Inline(lhs), Repr::Inline(rhs)) => match (lhs, rhs) { (Inline::Unsigned(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); - unsigned_op(lhs, rhs); + (ops.unsigned_op)(lhs, rhs); return VmResult::Ok(()); } (Inline::Signed(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); - signed_op(lhs, rhs); + (ops.signed_op)(lhs, rhs); return VmResult::Ok(()); } (Inline::Bool(lhs), Inline::Bool(rhs)) => { - bool_op(lhs, *rhs); + (ops.bool_op)(lhs, *rhs); return VmResult::Ok(()); } (lhs, rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { - op: protocol.name, + op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), }); @@ -1538,7 +1532,7 @@ impl Vm { }, (Repr::Inline(lhs), rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { - op: protocol.name, + op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), }); @@ -1551,12 +1545,12 @@ impl Vm { TargetValue::Fallback(fallback) => fallback, }; - self.target_fallback_assign(fallback, protocol) + self.target_fallback_assign(fallback, ops.protocol) } fn internal_shift( &mut self, - protocol: Protocol, + protocol: &Protocol, error: fn() -> VmErrorKind, signed_op: fn(i64, u32) -> Option, unsigned_op: fn(u64, u32) -> Option, @@ -1653,30 +1647,27 @@ impl Vm { fn internal_bitwise_assign( &mut self, target: InstTarget, - protocol: Protocol, - error: fn() -> VmErrorKind, - signed_op: fn(i64, u32) -> Option, - unsigned_op: fn(u64, u32) -> Option, + ops: &'static ShiftOps, rhs: InstAddress, ) -> VmResult<()> { let fallback = match vm_try!(target_value(&mut self.stack, &self.unit, target, rhs)) { TargetValue::Same(value) => { match value.as_mut() { Repr::Inline(Inline::Unsigned(value)) => { - let shift = vm_try!(u32::try_from(*value).ok().ok_or_else(error)); - let out = vm_try!(unsigned_op(*value, shift).ok_or_else(error)); + let shift = vm_try!(u32::try_from(*value).ok().ok_or_else(ops.error)); + let out = vm_try!((ops.unsigned_op)(*value, shift).ok_or_else(ops.error)); *value = out; return VmResult::Ok(()); } Repr::Inline(Inline::Signed(value)) => { - let shift = vm_try!(u32::try_from(*value).ok().ok_or_else(error)); - let out = vm_try!(signed_op(*value, shift).ok_or_else(error)); + let shift = vm_try!(u32::try_from(*value).ok().ok_or_else(ops.error)); + let out = vm_try!((ops.signed_op)(*value, shift).ok_or_else(ops.error)); *value = out; return VmResult::Ok(()); } Repr::Inline(value) => { return err(VmErrorKind::UnsupportedBinaryOperation { - op: protocol.name, + op: ops.protocol.name, lhs: value.type_info(), rhs: value.type_info(), }); @@ -1691,19 +1682,19 @@ impl Vm { (Repr::Inline(lhs), Repr::Inline(rhs)) => match (lhs, rhs) { (Inline::Unsigned(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); - let out = vm_try!(unsigned_op(*lhs, rhs).ok_or_else(error)); + let out = vm_try!((ops.unsigned_op)(*lhs, rhs).ok_or_else(ops.error)); *lhs = out; return VmResult::Ok(()); } (Inline::Signed(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); - let out = vm_try!(signed_op(*lhs, rhs).ok_or_else(error)); + let out = vm_try!((ops.signed_op)(*lhs, rhs).ok_or_else(ops.error)); *lhs = out; return VmResult::Ok(()); } (lhs, rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { - op: protocol.name, + op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), }); @@ -1711,7 +1702,7 @@ impl Vm { }, (Repr::Inline(lhs), rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { - op: protocol.name, + op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), }); @@ -1724,7 +1715,7 @@ impl Vm { TargetValue::Fallback(fallback) => fallback, }; - self.target_fallback_assign(fallback, protocol) + self.target_fallback_assign(fallback, ops.protocol) } #[cfg_attr(feature = "bench", inline(never))] @@ -1961,7 +1952,7 @@ impl Vm { match op { InstOp::Add => { vm_try!(self.internal_num( - Protocol::ADD, + &Protocol::ADD, || VmErrorKind::Overflow, i64::checked_add, u64::checked_add, @@ -1973,7 +1964,7 @@ impl Vm { } InstOp::Sub => { vm_try!(self.internal_num( - Protocol::SUB, + &Protocol::SUB, || VmErrorKind::Underflow, i64::checked_sub, u64::checked_sub, @@ -1985,7 +1976,7 @@ impl Vm { } InstOp::Mul => { vm_try!(self.internal_num( - Protocol::MUL, + &Protocol::MUL, || VmErrorKind::Overflow, i64::checked_mul, u64::checked_mul, @@ -1997,7 +1988,7 @@ impl Vm { } InstOp::Div => { vm_try!(self.internal_num( - Protocol::DIV, + &Protocol::DIV, || VmErrorKind::DivideByZero, i64::checked_div, u64::checked_div, @@ -2009,7 +2000,7 @@ impl Vm { } InstOp::Rem => { vm_try!(self.internal_num( - Protocol::REM, + &Protocol::REM, || VmErrorKind::DivideByZero, i64::checked_rem, u64::checked_rem, @@ -2022,7 +2013,7 @@ impl Vm { InstOp::BitAnd => { use ops::BitAnd as _; vm_try!(self.internal_bit( - Protocol::BIT_AND, + &Protocol::BIT_AND, i64::bitand, u64::bitand, bool::bitand, @@ -2034,7 +2025,7 @@ impl Vm { InstOp::BitXor => { use ops::BitXor as _; vm_try!(self.internal_bit( - Protocol::BIT_XOR, + &Protocol::BIT_XOR, i64::bitxor, u64::bitxor, bool::bitxor, @@ -2046,7 +2037,7 @@ impl Vm { InstOp::BitOr => { use ops::BitOr as _; vm_try!(self.internal_bit( - Protocol::BIT_OR, + &Protocol::BIT_OR, i64::bitor, u64::bitor, bool::bitor, @@ -2057,7 +2048,7 @@ impl Vm { } InstOp::Shl => { vm_try!(self.internal_shift( - Protocol::SHL, + &Protocol::SHL, || VmErrorKind::Overflow, i64::checked_shl, u64::checked_shl, @@ -2068,7 +2059,7 @@ impl Vm { } InstOp::Shr => { vm_try!(self.internal_shift( - Protocol::SHR, + &Protocol::SHR, || VmErrorKind::Underflow, i64::checked_shr, u64::checked_shr, @@ -2151,120 +2142,129 @@ impl Vm { } #[cfg_attr(feature = "bench", inline(never))] - fn op_assign( + fn op_assign_arithmetic( &mut self, - op: InstAssignOp, + op: InstArithmeticOp, target: InstTarget, value: InstAddress, ) -> VmResult<()> { - match op { - InstAssignOp::Add => { - vm_try!(self.internal_num_assign( - target, - Protocol::ADD_ASSIGN, - || VmErrorKind::Overflow, - i64::checked_add, - u64::checked_add, - ops::Add::add, - value, - )); - } - InstAssignOp::Sub => { - vm_try!(self.internal_num_assign( - target, - Protocol::SUB_ASSIGN, - || VmErrorKind::Underflow, - i64::checked_sub, - u64::checked_sub, - ops::Sub::sub, - value, - )); - } - InstAssignOp::Mul => { - vm_try!(self.internal_num_assign( - target, - Protocol::MUL_ASSIGN, - || VmErrorKind::Overflow, - i64::checked_mul, - u64::checked_mul, - ops::Mul::mul, - value, - )); - } - InstAssignOp::Div => { - vm_try!(self.internal_num_assign( - target, - Protocol::DIV_ASSIGN, - || VmErrorKind::DivideByZero, - i64::checked_div, - u64::checked_div, - ops::Div::div, - value, - )); - } - InstAssignOp::Rem => { - vm_try!(self.internal_num_assign( - target, - Protocol::REM_ASSIGN, - || VmErrorKind::DivideByZero, - i64::checked_rem, - u64::checked_rem, - ops::Rem::rem, - value, - )); - } - InstAssignOp::BitAnd => { - vm_try!(self.internal_infallible_bitwise_assign( - target, - Protocol::BIT_AND_ASSIGN, - ops::BitAndAssign::bitand_assign, - ops::BitAndAssign::bitand_assign, - ops::BitAndAssign::bitand_assign, - value, - )); - } - InstAssignOp::BitXor => { - vm_try!(self.internal_infallible_bitwise_assign( - target, - Protocol::BIT_XOR_ASSIGN, - ops::BitXorAssign::bitxor_assign, - ops::BitXorAssign::bitxor_assign, - ops::BitXorAssign::bitxor_assign, - value, - )); - } - InstAssignOp::BitOr => { - vm_try!(self.internal_infallible_bitwise_assign( - target, - Protocol::BIT_OR_ASSIGN, - ops::BitOrAssign::bitor_assign, - ops::BitOrAssign::bitor_assign, - ops::BitOrAssign::bitor_assign, - value, - )); - } - InstAssignOp::Shl => { - vm_try!(self.internal_bitwise_assign( - target, - Protocol::SHL_ASSIGN, - || VmErrorKind::Overflow, - i64::checked_shl, - u64::checked_shl, - value, - )); - } - InstAssignOp::Shr => { - vm_try!(self.internal_bitwise_assign( - target, - Protocol::SHR_ASSIGN, - || VmErrorKind::Underflow, - i64::checked_shr, - u64::checked_shr, - value, - )); - } - } + static ADD: ArithmeticOps = ArithmeticOps { + protocol: &Protocol::ADD_ASSIGN, + error: || VmErrorKind::Overflow, + signed_op: i64::checked_add, + unsigned_op: u64::checked_add, + float_op: ops::Add::add, + }; + + static SUB: ArithmeticOps = ArithmeticOps { + protocol: &Protocol::SUB_ASSIGN, + error: || VmErrorKind::Underflow, + signed_op: i64::checked_sub, + unsigned_op: u64::checked_sub, + float_op: ops::Add::add, + }; + + static MUL: ArithmeticOps = ArithmeticOps { + protocol: &Protocol::MUL_ASSIGN, + error: || VmErrorKind::Overflow, + signed_op: i64::checked_mul, + unsigned_op: u64::checked_mul, + float_op: ops::Add::add, + }; + + static DIV: ArithmeticOps = ArithmeticOps { + protocol: &Protocol::DIV_ASSIGN, + error: || VmErrorKind::DivideByZero, + signed_op: i64::checked_div, + unsigned_op: u64::checked_div, + float_op: ops::Add::add, + }; + + static REM: ArithmeticOps = ArithmeticOps { + protocol: &Protocol::REM_ASSIGN, + error: || VmErrorKind::DivideByZero, + signed_op: i64::checked_rem, + unsigned_op: u64::checked_rem, + float_op: ops::Rem::rem, + }; + + let ops = match op { + InstArithmeticOp::Add => &ADD, + InstArithmeticOp::Sub => &SUB, + InstArithmeticOp::Mul => &MUL, + InstArithmeticOp::Div => &DIV, + InstArithmeticOp::Rem => &REM, + }; + + vm_try!(self.internal_num_assign(target, ops, value)); + VmResult::Ok(()) + } + + #[cfg_attr(feature = "bench", inline(never))] + fn op_assign_bitwise( + &mut self, + op: InstBitwiseOp, + target: InstTarget, + value: InstAddress, + ) -> VmResult<()> { + static BIT_AND: BitwiseOps = BitwiseOps { + protocol: &Protocol::BIT_AND_ASSIGN, + signed_op: ops::BitAndAssign::bitand_assign, + unsigned_op: ops::BitAndAssign::bitand_assign, + bool_op: ops::BitAndAssign::bitand_assign, + }; + + static BIT_XOR: BitwiseOps = BitwiseOps { + protocol: &Protocol::BIT_XOR_ASSIGN, + signed_op: ops::BitXorAssign::bitxor_assign, + unsigned_op: ops::BitXorAssign::bitxor_assign, + bool_op: ops::BitXorAssign::bitxor_assign, + }; + + static BIT_OR: BitwiseOps = BitwiseOps { + protocol: &Protocol::BIT_OR_ASSIGN, + signed_op: ops::BitOrAssign::bitor_assign, + unsigned_op: ops::BitOrAssign::bitor_assign, + bool_op: ops::BitOrAssign::bitor_assign, + }; + let ops = match op { + InstBitwiseOp::BitAnd => &BIT_AND, + InstBitwiseOp::BitXor => &BIT_XOR, + InstBitwiseOp::BitOr => &BIT_OR, + }; + + vm_try!(self.internal_infallible_bitwise_assign(target, ops, value,)); + VmResult::Ok(()) + } + + #[cfg_attr(feature = "bench", inline(never))] + fn op_assign_shift( + &mut self, + op: InstShiftOp, + target: InstTarget, + value: InstAddress, + ) -> VmResult<()> { + static SHL: ShiftOps = ShiftOps { + protocol: &Protocol::SHL_ASSIGN, + error: || VmErrorKind::Overflow, + signed_op: i64::checked_shl, + unsigned_op: u64::checked_shl, + }; + + static SHR: ShiftOps = ShiftOps { + protocol: &Protocol::SHR_ASSIGN, + error: || VmErrorKind::Underflow, + signed_op: i64::checked_shr, + unsigned_op: u64::checked_shr, + }; + + let ops = match op { + InstShiftOp::Shl => &SHL, + InstShiftOp::Shr => &SHR, + }; + + vm_try!(self.internal_bitwise_assign(target, ops, value)); VmResult::Ok(()) } @@ -2295,7 +2295,7 @@ impl Vm { if let CallResult::Unsupported(target) = vm_try!(self.call_instance_fn( Isolated::None, target, - Protocol::INDEX_SET, + &Protocol::INDEX_SET, &mut args, Output::discard() )) { @@ -2437,7 +2437,7 @@ impl Vm { if let CallResult::Unsupported(target) = vm_try!(self.call_instance_fn( Isolated::None, target, - Protocol::INDEX_GET, + &Protocol::INDEX_GET, &mut args, out )) { @@ -2492,7 +2492,7 @@ impl Vm { let value = value.clone(); if let CallResult::Unsupported(value) = - vm_try!(self.call_index_fn(Protocol::GET, value, index, &mut (), out)) + vm_try!(self.call_index_fn(&Protocol::GET, value, index, &mut (), out)) { return err(VmErrorKind::UnsupportedTupleIndexGet { target: value.type_info(), @@ -2530,7 +2530,7 @@ impl Vm { let mut args = DynGuardedArgs::new((value,)); let result = - vm_try!(self.call_field_fn(Protocol::SET, target, hash, &mut args, Output::discard())); + vm_try!(self.call_field_fn(&Protocol::SET, target, hash, &mut args, Output::discard())); if let CallResult::Unsupported(target) = result { return err(VmErrorKind::UnsupportedObjectSlotIndexSet { @@ -2587,7 +2587,7 @@ impl Vm { let target = target.clone(); if let CallResult::Unsupported(target) = - vm_try!(self.call_field_fn(Protocol::GET, target, index.hash(), &mut (), out)) + vm_try!(self.call_field_fn(&Protocol::GET, target, index.hash(), &mut (), out)) { return err(VmErrorKind::UnsupportedObjectSlotIndexGet { target: target.type_info(), @@ -2783,7 +2783,7 @@ impl Vm { value.clone() }; - match vm_try!(self.try_call_protocol_fn(Protocol::TRY, value, &mut ())) { + match vm_try!(self.try_call_protocol_fn(&Protocol::TRY, value, &mut ())) { CallResultOnly::Ok(value) => vm_try!(ControlFlow::from_value(value)), CallResultOnly::Unsupported(target) => { return err(VmErrorKind::UnsupportedTryOperand { @@ -2976,7 +2976,7 @@ impl Vm { let value = value.clone(); match vm_try!(self.try_call_protocol_fn( - Protocol::IS_VARIANT, + &Protocol::IS_VARIANT, value, &mut Some((index,)) )) { @@ -3624,8 +3624,14 @@ impl Vm { Inst::Op { op, a, b, out } => { vm_try!(self.op_op(op, a, b, out)); } - Inst::Assign { op, target, value } => { - vm_try!(self.op_assign(op, target, value)); + Inst::AssignArithmetic { op, target, value } => { + vm_try!(self.op_assign_arithmetic(op, target, value)); + } + Inst::AssignBitwise { op, target, value } => { + vm_try!(self.op_assign_bitwise(op, target, value)); + } + Inst::AssignShift { op, target, value } => { + vm_try!(self.op_assign_shift(op, target, value)); } Inst::IterNext { addr, jump, out } => { vm_try!(self.op_iter_next(addr, jump, out)); @@ -3717,6 +3723,28 @@ fn check_args(args: usize, expected: usize) -> Result<(), VmErrorKind> { Ok(()) } +struct ArithmeticOps { + protocol: &'static Protocol, + error: fn() -> VmErrorKind, + signed_op: fn(i64, i64) -> Option, + unsigned_op: fn(u64, u64) -> Option, + float_op: fn(f64, f64) -> f64, +} + +struct BitwiseOps { + protocol: &'static Protocol, + signed_op: fn(&mut i64, i64), + unsigned_op: fn(&mut u64, u64), + bool_op: fn(&mut bool, bool), +} + +struct ShiftOps { + protocol: &'static Protocol, + error: fn() -> VmErrorKind, + signed_op: fn(i64, u32) -> Option, + unsigned_op: fn(u64, u32) -> Option, +} + enum TargetFallback { Value(Value, Value), Field(Value, Hash, Value), diff --git a/crates/rune/src/runtime/vm_error.rs b/crates/rune/src/runtime/vm_error.rs index 3166f0123..2c265932a 100644 --- a/crates/rune/src/runtime/vm_error.rs +++ b/crates/rune/src/runtime/vm_error.rs @@ -677,7 +677,7 @@ pub(crate) enum VmErrorKind { hash: Hash, }, MissingProtocolFunction { - protocol: Protocol, + protocol: &'static Protocol, instance: TypeInfo, }, MissingInstanceFunction {