Skip to content

Commit

Permalink
Update rebind macro to be more ergonomic
Browse files Browse the repository at this point in the history
  • Loading branch information
CeleritasCelery committed Apr 29, 2023
1 parent 6b54612 commit 5f10c29
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,7 +1041,7 @@ mod test {
cx: &mut Context,
) {
root!(env, Env::default(), cx);
let val = rebind!(call(bytecode, args, "test", env, cx).unwrap(), cx);
let val = rebind!(call(bytecode, args, "test", env, cx).unwrap());
let expect = expect.bind(cx);
assert_eq!(val, expect);
}
Expand Down
32 changes: 27 additions & 5 deletions src/core/gc/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,21 +259,43 @@ impl<const CONST: bool> Drop for Block<CONST> {
}
}

// helper macro for the `rebind!` macro
macro_rules! last {
($arg:expr) => { $arg };
($head:expr, $($rest:expr),+) => {
last!($($rest),+)
};
}

/// Rebinds an object so that it is bound to an immutable borrow of [Context]
/// instead of a mutable borrow. This can release the mutable borrow and allow
/// Context to be used for other things.
///
/// # Examples
///
/// ```
/// let object = func_taking_mut_context(&mut cx);
/// rebind!(object, cx);
/// let object = rebind!(func1(&mut cx));
/// func2(&mut cx);
/// let object2 = object;
/// ```
///
/// wthout this macro the above code would not compile because `object` can't
/// outlive the call to func2.
#[macro_export]
macro_rules! rebind {
($value:expr, $cx:ident) => {{
// rebind!(func(x, cx)?)
($($path:ident).*($($arg:expr),+)$($x:tt)?) => {{
rebind!($($path).*($($arg),+)$($x)?, last!($($arg),+))
}};
// rebind!(func(x, cx).unwrap())
($($path:ident).*($($arg:expr),+).unwrap()) => {{
rebind!($($path).*($($arg),+).unwrap(), last!($($arg),+))
}};
// rebind!(x, cx)
($value:expr, $cx:expr) => {{
let bits = $value.into_raw();
unsafe { $cx.rebind_raw_ptr(bits) }
#[allow(clippy::unnecessary_mut_passed)]
unsafe { $crate::core::gc::Context::rebind_raw_ptr($cx, bits) }
}};
}

Expand All @@ -290,7 +312,7 @@ mod test {
fn test_reborrow() {
let roots = &RootSet::default();
let mut cx = Context::new(roots);
let obj = rebind!(bind_to_mut(&mut cx), cx);
let obj = rebind!(bind_to_mut(&mut cx));
_ = "foo".into_obj(&cx);
assert_eq!(obj, "invariant");
}
Expand Down
12 changes: 6 additions & 6 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl Interpreter<'_> {
root!(name, cx);
let value = match forms.next() {
// (defvar x y)
Some(value) => rebind!(self.eval_form(value, cx)?, cx),
Some(value) => rebind!(self.eval_form(value, cx)?),
// (defvar x)
None => nil(),
};
Expand Down Expand Up @@ -316,7 +316,7 @@ impl Interpreter<'_> {
(Object::Symbol(var), Some(val)) => {
root!(var, cx);
root!(val, cx);
let val = rebind!(self.eval_form(val, cx)?, cx);
let val = rebind!(self.eval_form(val, cx)?);
self.var_set(var.bind(cx), val, cx)?;
last_value.set(val);
}
Expand Down Expand Up @@ -393,7 +393,7 @@ impl Interpreter<'_> {
} else {
self.let_bind_serial(obj, cx)
}?;
let obj = rebind!(self.implicit_progn(iter, cx)?, cx);
let obj = rebind!(self.implicit_progn(iter, cx)?);
// Remove old bindings
self.vars.truncate(prev_len);
self.env.unbind(varbind_count, cx);
Expand All @@ -408,7 +408,7 @@ impl Interpreter<'_> {
// (let ((x y)))
Object::Cons(_) => {
let cons = binding.as_cons();
let val = rebind!(self.let_bind_value(cons, cx)?, cx);
let val = rebind!(self.let_bind_value(cons, cx)?);
let var: Symbol = cons
.get(cx)
.car()
Expand All @@ -435,7 +435,7 @@ impl Interpreter<'_> {
// (let ((x y)))
Object::Cons(_) => {
let cons = binding.as_cons();
let var = rebind!(self.let_bind_value(cons, cx)?, cx);
let var = rebind!(self.let_bind_value(cons, cx)?);
let sym: Symbol = cons
.get(cx)
.car()
Expand Down Expand Up @@ -762,7 +762,7 @@ mod test {
println!("Test String: {test_str}");
let obj = crate::reader::read(test_str, cx).unwrap().0;
root!(obj, cx);
let compare = rebind!(eval(obj, None, env, cx).unwrap(), cx);
let compare = rebind!(eval(obj, None, env, cx).unwrap());
let expect: GcObj = expect.into_obj(cx).copy_as_obj();
assert_eq!(compare, expect);
}
Expand Down

0 comments on commit 5f10c29

Please sign in to comment.