Skip to content

Commit

Permalink
rune: Improve field operations
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Nov 5, 2024
1 parent 466b829 commit 471a60c
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 108 deletions.
173 changes: 85 additions & 88 deletions crates/rune-macros/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,51 @@ impl Context {
};
}

macro_rules! generate {
($proto:ident, $op:tt) => {
|g| {
let Generate {
ty,
target,
field,
protocol,
..
} = g;

let protocol_field = g.tokens.protocol(&Protocol::$proto);

match target {
GenerateTarget::Named { field_ident, field_name } => {
if let Some(custom) = &protocol.custom {
quote_spanned! { field.span() =>
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| {
s.#field_ident $op value
})?;
}
}
}
GenerateTarget::Numbered { field_index } => {
if let Some(custom) = &protocol.custom {
quote_spanned! { field.span() =>
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| {
s.#field_index $op value
})?;
}
}
}
}
}
};
}

let mut attr = FieldAttrs::default();

for a in input {
Expand All @@ -314,6 +359,35 @@ impl Context {
}

let result = a.parse_nested_meta(|meta| {
macro_rules! field_functions {
(
$(
$assign:literal, $assign_proto:ident, [$($assign_op:tt)*],
$op:literal, $op_proto:ident, [$($op_op:tt)*],
)*
) => {{
$(
if meta.path.is_ident($assign) {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate_assign!($assign_proto, $($assign_op)*),
});

return Ok(());
}

if meta.path.is_ident($op) {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate!($op_proto, $($op_op)*),
});

return Ok(());
}
)*
}};
}

if meta.path.is_ident("id") {
attr.id = Some(meta.path.span());
return Ok(());
Expand Down Expand Up @@ -451,94 +525,17 @@ impl Context {
return Ok(());
}

if meta.path.is_ident("add_assign") {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate_assign!(ADD_ASSIGN, +=),
});

return Ok(());
}

if meta.path.is_ident("sub_assign") {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate_assign!(SUB_ASSIGN, -=),
});

return Ok(());
}

if meta.path.is_ident("div_assign") {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate_assign!(DIV_ASSIGN, /=),
});

return Ok(());
}

if meta.path.is_ident("mul_assign") {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate_assign!(MUL_ASSIGN, *=),
});

return Ok(());
}

if meta.path.is_ident("bit_and_assign") {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate_assign!(BIT_AND_ASSIGN, &=),
});

return Ok(());
}

if meta.path.is_ident("bit_or_assign") {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate_assign!(BIT_OR_ASSIGN, |=),
});

return Ok(());
}

if meta.path.is_ident("bit_xor_assign") {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate_assign!(BIT_XOR_ASSIGN, ^=),
});

return Ok(());
}

if meta.path.is_ident("shl_assign") {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate_assign!(SHL_ASSIGN, <<=),
});

return Ok(());
}

if meta.path.is_ident("shr_assign") {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate_assign!(SHR_ASSIGN, >>=),
});

return Ok(());
}

if meta.path.is_ident("rem_assign") {
attr.protocols.push(FieldProtocol {
custom: self.parse_field_custom(meta.input)?,
generate: generate_assign!(REM_ASSIGN, %=),
});

return Ok(());
field_functions! {
"add_assign", ADD_ASSIGN, [+=], "add", ADD, [+],
"sub_assign", SUB_ASSIGN, [-=], "sub", SUB, [-],
"div_assign", DIV_ASSIGN, [/=], "div", DIV, [/],
"mul_assign", MUL_ASSIGN, [*=], "mul", MUL, [*],
"rem_assign", REM_ASSIGN, [%=], "rem", REM, [%],
"bit_and_assign", BIT_AND_ASSIGN, [&=], "bit_and", BIT_AND, [&],
"bit_or_assign", BIT_OR_ASSIGN, [|=], "bit_or", BIT_OR, [|],
"bit_xor_assign", BIT_XOR_ASSIGN, [^=], "bit_xor", BIT_XOR, [^],
"shl_assign", SHL_ASSIGN, [<<=], "shl", SHL, [<<],
"shr_assign", SHR_ASSIGN, [>>=], "shr", SHR, [>>],
}

Err(syn::Error::new_spanned(&meta.path, "Unsupported attribute"))
Expand Down
7 changes: 7 additions & 0 deletions crates/rune/src/runtime/static_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ impl AsRef<String> for StaticString {
}
}

impl fmt::Display for StaticString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}

impl fmt::Debug for StaticString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down
21 changes: 19 additions & 2 deletions crates/rune/src/runtime/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,7 @@ impl Vm {

VmResult::Ok(())
}
TargetFallback::Field(lhs, hash, rhs) => {
TargetFallback::Field(lhs, hash, slot, rhs) => {
let mut args = DynGuardedArgs::new((rhs,));

if let CallResult::Unsupported(lhs) = vm_try!(self.call_field_fn(
Expand All @@ -1222,8 +1222,13 @@ impl Vm {
&mut args,
Output::discard()
)) {
let Some(field) = self.unit.lookup_string(slot) else {
return err(VmErrorKind::MissingStaticString { slot });
};

return err(VmErrorKind::UnsupportedObjectSlotIndexGet {
target: lhs.type_info(),
field: field.clone(),
});
}

Expand Down Expand Up @@ -2213,8 +2218,13 @@ impl Vm {
vm_try!(self.call_field_fn(&Protocol::SET, target, hash, &mut args, Output::discard()));

if let CallResult::Unsupported(target) = result {
let Some(field) = self.unit.lookup_string(slot) else {
return err(VmErrorKind::MissingStaticString { slot });
};

return err(VmErrorKind::UnsupportedObjectSlotIndexSet {
target: target.type_info(),
field: field.clone(),
});
};

Expand Down Expand Up @@ -2260,6 +2270,7 @@ impl Vm {
target => {
return err(VmErrorKind::UnsupportedObjectSlotIndexGet {
target: target.type_info(),
field: index.clone(),
});
}
}
Expand All @@ -2269,8 +2280,13 @@ impl Vm {
if let CallResult::Unsupported(target) =
vm_try!(self.call_field_fn(&Protocol::GET, target, index.hash(), &mut (), out))
{
let Some(field) = self.unit.lookup_string(slot) else {
return err(VmErrorKind::MissingStaticString { slot });
};

return err(VmErrorKind::UnsupportedObjectSlotIndexGet {
target: target.type_info(),
field: field.clone(),
});
}

Expand Down Expand Up @@ -3414,7 +3430,7 @@ fn check_args(args: usize, expected: usize) -> Result<(), VmErrorKind> {

enum TargetFallback {
Value(Value, Value),
Field(Value, Hash, Value),
Field(Value, Hash, usize, Value),
Index(Value, usize, Value),
}

Expand Down Expand Up @@ -3468,6 +3484,7 @@ fn target_value<'a>(
Ok(TargetValue::Fallback(TargetFallback::Field(
lhs.clone(),
field.hash(),
slot,
rhs.clone(),
)))
}
Expand Down
17 changes: 10 additions & 7 deletions crates/rune/src/runtime/vm_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ use crate::alloc::prelude::*;
use crate::alloc::{self, String};
use crate::compile::meta;
use crate::runtime::unit::{BadInstruction, BadJump};
use crate::runtime::{
use crate::{Any, Hash, ItemBuf};

use super::{
AccessError, AccessErrorKind, AnyObjError, AnyObjErrorKind, AnyTypeInfo, BoxedPanic, CallFrame,
DynArgsUsed, DynamicTakeError, ExecutionState, MaybeTypeOf, Panic, Protocol, SliceError,
StackError, TypeInfo, TypeOf, Unit, Vm, VmHaltInfo,
StackError, StaticString, TypeInfo, TypeOf, Unit, Vm, VmHaltInfo,
};
use crate::{Any, Hash, ItemBuf};

/// A virtual machine error which includes tracing information.
pub struct VmError {
Expand Down Expand Up @@ -741,9 +742,11 @@ pub(crate) enum VmErrorKind {
},
UnsupportedObjectSlotIndexGet {
target: TypeInfo,
field: Arc<StaticString>,
},
UnsupportedObjectSlotIndexSet {
target: TypeInfo,
field: Arc<StaticString>,
},
UnsupportedIs {
value: TypeInfo,
Expand Down Expand Up @@ -962,11 +965,11 @@ impl fmt::Display for VmErrorKind {
f,
"The tuple index set operation is not supported on `{target}`",
),
VmErrorKind::UnsupportedObjectSlotIndexGet { target } => {
write!(f, "Field not available to get on `{target}`")
VmErrorKind::UnsupportedObjectSlotIndexGet { target, field } => {
write!(f, "Field `{field}` not available on `{target}`")
}
VmErrorKind::UnsupportedObjectSlotIndexSet { target } => {
write!(f, "Field not available to set on `{target}`")
VmErrorKind::UnsupportedObjectSlotIndexSet { target, field } => {
write!(f, "Field `{field}` not available to set on `{target}`")
}
VmErrorKind::UnsupportedIs { value, test_type } => {
write!(f, "Operation `{value} is {test_type}` is not supported")
Expand Down
Loading

0 comments on commit 471a60c

Please sign in to comment.