#[macro_export]
macro_rules! define_builtins {
(
$(
$(#[$attr:meta])*
$variant:ident => $name:literal
),* $(,)?
) => {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Builtin {
$(
$(#[$attr])*
$variant,
)*
}
impl Builtin {
pub const fn name(&self) -> &'static str {
match self {
$(
Builtin::$variant => $name,
)*
}
}
pub const ALL: &'static [Builtin] = &[
$(
Builtin::$variant,
)*
];
#[inline]
pub fn from_usize(n: usize) -> Self {
Self::ALL.get(n).copied().unwrap_or(Self::ALL[0])
}
}
};
}
#[macro_export]
macro_rules! define_stdlib {
(
$(
$(#[$attr:meta])*
$variant:ident($name:literal, [$($param:literal),* $(,)?], $body:literal)
),* $(,)?
) => {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum StdLib {
$(
$(#[$attr])*
$variant,
)*
}
impl StdLib {
pub const fn name(&self) -> &'static str {
match self {
$(
StdLib::$variant => $name,
)*
}
}
pub const fn params(&self) -> &'static [&'static str] {
match self {
$(
StdLib::$variant => &[$($param),*],
)*
}
}
pub const fn body(&self) -> &'static str {
match self {
$(
StdLib::$variant => $body,
)*
}
}
pub const ALL: &'static [StdLib] = &[
$(
StdLib::$variant,
)*
];
}
};
}
macro_rules! impl_pack_unpack_refs {
(1, $pack_name:ident, $unpack_name:ident) => {
#[inline]
pub fn $pack_name(&self, a: ArenaIndex) -> ArenaResult<ArenaIndex> {
self.arena.alloc(Value::Ref(a))
}
#[inline]
pub fn $unpack_name(&self, data: ArenaIndex) -> ArenaResult<ArenaIndex> {
self.arena.get(data)?.as_ref().ok_or(ArenaError::InvalidIndex)
}
};
($n:expr, $pack_name:ident, $unpack_name:ident, $set_fn:ident, $get_fn:ident, [$($var:ident),+ $(,)?]) => {
#[inline]
pub fn $pack_name(&self, $($var: ArenaIndex),+) -> ArenaResult<ArenaIndex> {
let data = self.arena.alloc_contiguous($n, Value::Nil)?;
self.arena.$set_fn(data, $(Value::Ref($var)),+)?;
Ok(data)
}
#[inline]
pub fn $unpack_name(&self, data: ArenaIndex) -> ArenaResult<( $( impl_pack_unpack_refs!(@T $var) ),+ )> {
let ($($var),+) = self.arena.$get_fn(data)?;
match ($($var.as_ref()),+) {
($(Some($var)),+) => Ok(($($var),+)),
_ => Err(ArenaError::InvalidIndex),
}
}
};
(@T $var:ident) => { ArenaIndex };
}