mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 11:46:42 +01:00
131 lines
4.7 KiB
Rust
131 lines
4.7 KiB
Rust
use crate::*;
|
|
|
|
/** Implement `Command` for given `State` and collection
|
|
* of `Variant` to `handler` mappings. */
|
|
#[macro_export] macro_rules! defcom {
|
|
([$self:ident, $state:ident:$State:ty] $(($Command:ident $((
|
|
$Variant:ident [$($($param:ident: $Param:ty),+)?] $expr:expr
|
|
))*))*) => {
|
|
$(#[derive(Clone, Debug)] pub enum $Command {
|
|
$($Variant $(($($Param),+))?),*
|
|
})*
|
|
$(command!(|$self: $Command, $state: $State|match $self {
|
|
$($Command::$Variant $(($($param),+))? => $expr),*
|
|
});)*
|
|
};
|
|
(|$self:ident, $state:ident:$State:ty| $($Command:ident { $(
|
|
$Variant:ident $(($($param:ident: $Param:ty),+))? => $expr:expr
|
|
)* $(,)? })*) => {
|
|
$(#[derive(Clone, Debug)] pub enum $Command {
|
|
$($Variant $(($($Param),+))?),*
|
|
})*
|
|
$(command!(|$self: $Command, $state: $State|match $self {
|
|
$($Command::$Variant $(($($param),+))? => $expr),*
|
|
});)*
|
|
};
|
|
}
|
|
|
|
/** Implement `Command` for given `State` and `handler` */
|
|
#[macro_export] macro_rules! command {
|
|
($(<$($l:lifetime),+>)?|$self:ident:$Command:ty,$state:ident:$State:ty|$handler:expr) => {
|
|
impl$(<$($l),+>)? Command<$State> for $Command {
|
|
fn execute ($self, $state: &mut $State) -> Perhaps<Self> {
|
|
Ok($handler)
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/** Implement `DslCommand` for given `State` and `Command` */
|
|
#[cfg(feature = "dsl")]
|
|
#[macro_export] macro_rules! atom_command {
|
|
($Command:ty : |$state:ident:<$State:ident: $Trait:path>| { $((
|
|
// identifier
|
|
$key:literal [
|
|
// named parameters
|
|
$(
|
|
// argument name
|
|
$arg:ident
|
|
// if type is not provided defaults to Dsl
|
|
$(
|
|
// type:name separator
|
|
:
|
|
// argument type
|
|
$type:ty
|
|
)?
|
|
),*
|
|
// rest of parameters
|
|
$(, ..$rest:ident)?
|
|
]
|
|
// bound command:
|
|
$command:expr
|
|
))* }) => {
|
|
impl<'a, $State: $Trait> TryFromDsl<'a, $State> for $Command {
|
|
fn try_from_expr ($state: &$State, iter: TokenIter) -> Option<Self> {
|
|
let iter = iter.clone();
|
|
match iter.next() {
|
|
$(Some(Token { value: Value::Key($key), .. }) => {
|
|
let iter = iter.clone();
|
|
$(
|
|
let next = iter.next();
|
|
if next.is_none() { panic!("no argument: {}", stringify!($arg)); }
|
|
let $arg = next.unwrap();
|
|
$(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)?
|
|
)*
|
|
$(let $rest = iter.clone();)?
|
|
return $command
|
|
},)*
|
|
_ => None
|
|
}
|
|
None
|
|
}
|
|
}
|
|
};
|
|
($Command:ty : |$state:ident:$State:ty| { $((
|
|
// identifier
|
|
$key:literal [
|
|
// named parameters
|
|
$(
|
|
// argument name
|
|
$arg:ident
|
|
// if type is not provided defaults to Dsl
|
|
$(
|
|
// type:name separator
|
|
:
|
|
// argument type
|
|
$type:ty
|
|
)?
|
|
),*
|
|
// rest of parameters
|
|
$(, ..$rest:ident)?
|
|
]
|
|
// bound command:
|
|
$command:expr
|
|
))* }) => {
|
|
impl<'a> TryFromDsl<'a, $State> for $Command {
|
|
fn try_from_expr ($state: &$State, iter: TokenIter) -> Option<Self> {
|
|
let mut iter = iter.clone();
|
|
match iter.next() {
|
|
$(Some(Token { value: Value::Key($key), .. }) => {
|
|
let mut iter = iter.clone();
|
|
$(
|
|
let next = iter.next();
|
|
if next.is_none() { panic!("no argument: {}", stringify!($arg)); }
|
|
let $arg = next.unwrap();
|
|
$(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)?
|
|
)*
|
|
$(let $rest = iter.clone();)?
|
|
return $command
|
|
}),*
|
|
_ => None
|
|
}
|
|
}
|
|
}
|
|
};
|
|
(@bind $state:ident =>$arg:ident ? : $type:ty) => {
|
|
let $arg: Option<$type> = Context::<$type>::get($state, $arg);
|
|
};
|
|
(@bind $state:ident => $arg:ident : $type:ty) => {
|
|
let $arg: $type = Context::<$type>::get_or_fail($state, $arg);
|
|
};
|
|
}
|