Skip to content

Instantly share code, notes, and snippets.

@porglezomp
Last active December 9, 2017 06:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save porglezomp/9999fb634819ab4c12ae29080aff08ef to your computer and use it in GitHub Desktop.
Save porglezomp/9999fb634819ab4c12ae29080aff08ef to your computer and use it in GitHub Desktop.
the great and terrible macro DSL
// this is the embedded DSL
tasks! {
heap h;
task {
loop {
wait for AbsDiff(1, 2);
[3] = h[&1] - h[&2];
if (h[&3] > 0) {
print h[&3];
} else {
print -h[&3];
}
}
}
task {
send AbsDiff(42, 13);
wait;
send AbsDiff(13, 42);
wait;
send AbsDiff(21, 69);
}
};
// this is the code it expands into
{
#[allow(unused)]
fn hide_scope() -> Program {
use Cmd::*;
let mut program = Program::new();
program.add_task(vec![
Loop(vec![
WaitFor("AbsDiff", vec![1, 2], None),
Set(3, Fun(|h| h[&1] - h[&2], "h[&1] - h[&2]")),
If(
Fun(|h| h[&3] > 0, "h[&3] > 0"),
vec![Print(Fun(|h| h[&3], "h[&3]"))],
vec![Print(::Fun(|h| -h[&3], "-h[&3]"))]
),
]),
]);
program.add_task(vec![
SendMsg(
"AbsDiff",
vec![::Fun(|h| 42, "42"), ::Fun(|h| 13, "13")]
),
Wait,
SendMsg(
"AbsDiff",
vec![::Fun(|h| 13, "13"), ::Fun(|h| 42, "42")]
),
Wait,
SendMsg(
"AbsDiff",
vec![::Fun(|h| 21, "21"), ::Fun(|h| 69, "69")]
),
]);
program
}
hide_scope()
}
// this is the witchcraft
#[macro_export]
macro_rules! f {
(|$h:ident| $code:expr) => {
$crate::Fun(|$h| $code, stringify!($code))
}
}
#[macro_export]
macro_rules! cmds {
($h:ident ; [$($x:expr),*] ; ) => {
vec![$($x,)*]
};
(
$h:ident ; [$($x:expr),*] ;
loop { $($body:tt)* }
$($rest:tt)*
) => {
cmds!($h ; [$($x,)* Loop(cmds!($h ; [] ; $($body)*))] ; $($rest)*)
};
(
$h:ident ; [$($x:expr),*] ;
wait ;
$($rest:tt)*
) => {
cmds!($h ; [$($x,)* Wait] ; $($rest)*)
};
(
$h:ident ; [$($x:expr),*] ;
wait for $msg:ident ($($bind:expr),*) ;
$($rest:tt)*
) => {
cmds!($h ; [$($x,)* WaitFor(stringify!($msg), vec![$($bind),*], None)] ; $($rest)*)
};
(
$h:ident ; [$($x:expr),*] ;
send $msg:ident ($($arg:expr),*) ;
$($rest:tt)*
) => {
cmds!($h ; [$($x,)* SendMsg(stringify!($msg), vec![$(f!(|$h| $arg)),*])] ; $($rest)*)
};
(
$h:ident ; [$($x:expr),*] ;
print $msg:expr ;
$($rest:tt)*
) => {
cmds!($h ; [$($x,)* Print(f!(|$h| $msg))] ; $($rest)*)
};
(
$h:ident ; [$($x:expr),*] ;
[$var:expr] = $val:expr ;
$($rest:tt)*
) => {
cmds!($h ; [$($x,)* Set($var, f!(|$h| $val))] ; $($rest)*)
};
(
$h:ident ; [$($x:expr),*] ;
if ($cond:expr) { $($if_true:tt)* } else { $($if_false:tt)* }
$($rest:tt)*
) => {
cmds!($h ; [$($x,)* If(f!(|$h| $cond), cmds!($h ; [] ; $($if_true)*), cmds!($h ; [] ; $($if_false)*))] ; $($rest)*)
};
(
$h:ident ; [$($x:expr),*] ;
$e:expr ;
$($rest:tt)*
) => {
cmds!($h ; [$($x,)* $e] ; $($rest)*)
};
}
#[macro_export]
macro_rules! tasks {
(
heap $h:ident ;
$(task { $($cmd:tt)* })*
) => {{
#[allow(unused)]
fn hide_scope() -> $crate::Program {
use $crate::Cmd::*;
let mut program = $crate::Program::new();
$(
program.add_task(cmds!($h ; [] ; $($cmd)*));
)*;
program
}
hide_scope()
}}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment