use std::cell::RefCell;
use std::fmt::{Formatter,Result,Debug};
thread_local!(static NAME_COUNTER: RefCell<usize> = RefCell::new(0));
#[derive(PartialEq,Eq,Clone,Hash)]
pub struct ProgPt {
pub symbol:&'static str,
}
impl Debug for ProgPt {
fn fmt(&self, f: &mut Formatter) -> Result { self.symbol.fmt(f) }
}
pub fn bump_name_counter() -> usize {
NAME_COUNTER.with(|ctr|{let c = *ctr.borrow(); *ctr.borrow_mut() = c + 1; c})
}
#[macro_export]
macro_rules! prog_pt {
($symbol:expr) => {{
ProgPt{
symbol:$symbol,
}
}}
}
#[macro_export]
macro_rules! get {
($art:expr) => {{
force(&($art))
}}
}
#[macro_export]
macro_rules! cell {
($value:expr) => {{
cell(name_of_usize(bump_name_counter()), $value)
}}
}
#[macro_export]
macro_rules! thunk {
[ $suspended_body:expr ] => {{
thunk
(ArtIdChoice::Nominal(name_of_usize(bump_name_counter())),
prog_pt!(stringify!("anonymous")),
Rc::new(Box::new(
move |(),()|{
$suspended_body
})),
(),
()
)
}}
;
[ $nm:expr =>> $suspended_body:expr ] => {{
thunk
(ArtIdChoice::Nominal($nm),
prog_pt!(stringify!("anonymous")),
Rc::new(Box::new(
move |(),()|{
$suspended_body
})),
(),
()
)
}}
;
( $nm:expr =>> $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
thunk
(ArtIdChoice::Nominal($nm),
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*, _) = args ;
$f :: < $( $ty ),* >( $( $lab ),* )
})),
( $( $arg ),*, ()),
()
)
}}
;
( $nm:expr =>> $f:path , $( $lab:ident : $arg:expr ),* ) => {{
thunk
(ArtIdChoice::Nominal($nm),
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*, _) = args ;
$f ( $( $lab ),* )
})),
( $( $arg ),*, () ),
()
)
}}
;
( $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
thunk
(ArtIdChoice::Structural,
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*, _) = args ;
$f :: < $( $ty ),* >( $( $lab ),* )
})),
( $( $arg ),*, () ),
()
)
}}
;
( $f:path , $( $lab:ident : $arg:expr ),* ) => {{
thunk
(ArtIdChoice::Structural,
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*, _) = args ;
$f ( $( $lab ),* )
})),
( $( $arg ),*, () ),
()
)
}}
;
( $nm:expr =>> $f:ident =>> < $( $ty:ty ),* > , $( $lab1:ident : $arg1:expr ),* ;; $( $lab2:ident : $arg2:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Nominal($nm),
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args1, args2|{
let ($( $lab1 ),*, _) = args1 ;
let ($( $lab2 ),*, _) = args2 ;
$f :: < $( $ty ),* > ( $( $lab1 ),* , $( $lab2 ),* )
})),
( $( $arg1 ),*, () ),
( $( $arg2 ),*, () ),
);
t
}}
;
}
#[macro_export]
macro_rules! memo {
( $nm:expr =>> $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Nominal($nm),
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*) = args ;
$f :: < $( $ty ),* >( $( $lab ),* )
})),
( $( $arg ),*, ),
()
);
force(&t)
}}
;
( $nm:expr =>> $f:path , $( $lab:ident : $arg:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Nominal($nm),
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*) = args ;
$f ( $( $lab ),* )
})),
( $( $arg ),* ),
()
);
force(&t)
}}
;
( $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Structural,
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*) = args ;
$f :: < $( $ty ),* >( $( $lab ),* )
})),
( $( $arg ),* ),
()
);
force(&t)
}}
;
( $f:path , $( $lab:ident : $arg:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Structural,
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*, _) = args ;
$f ( $( $lab ),* )
})),
( $( $arg ),*, () ),
()
);
force(&t)
}}
;
( $nm:expr =>> $f:path , $( $lab1:ident : $arg1:expr ),* ;; $( $lab2:ident : $arg2:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Nominal($nm),
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args1, args2|{
let ($( $lab1 ),*, _) = args1 ;
let ($( $lab2 ),*, _) = args2 ;
$f ( $( $lab1 ),* , $( $lab2 ),* )
})),
( $( $arg1 ),*, () ),
( $( $arg2 ),*, () ),
);
force(&t)
}}
;
( $nm:expr =>> $f:ident =>> < $( $ty:ty ),* > , $( $lab1:ident : $arg1:expr ),* ;; $( $lab2:ident : $arg2:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Nominal($nm),
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args1, args2|{
let ($( $lab1 ),*, _) = args1 ;
let ($( $lab2 ),*, _) = args2 ;
$f :: < $( $ty ),* > ( $( $lab1 ),* , $( $lab2 ),* )
})),
( $( $arg1 ),*, () ),
( $( $arg2 ),*, () ),
);
force(&t)
}}
;
}
#[macro_export]
macro_rules! eager {
( $nm:expr =>> $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Nominal($nm),
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*) = args ;
$f :: < $( $ty ),* >( $( $lab ),* )
})),
( $( $arg ),*, ),
()
);
let res = force(&t) ;
(t, res)
}}
;
( $nm:expr =>> $f:path , $( $lab:ident : $arg:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Nominal($nm),
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*) = args ;
$f ( $( $lab ),* )
})),
( $( $arg ),* ),
()
);
let res = force(&t) ;
(t, res)
}}
;
( $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Structural,
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*) = args ;
$f :: < $( $ty ),* >( $( $lab ),* )
})),
( $( $arg ),* ),
()
);
let res = force(&t) ;
(t, res)
}}
;
( $f:path , $( $lab:ident : $arg:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Structural,
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args, _|{
let ($( $lab ),*, _) = args ;
$f ( $( $lab ),* )
})),
( $( $arg ),*, () ),
()
);
let res = force(&t) ;
(t, res)
}}
;
( $nm:expr =>> $f:ident =>> < $( $ty:ty ),* > , $( $lab1:ident : $arg1:expr ),* ;; $( $lab2:ident : $arg2:expr ),* ) => {{
let t = thunk
(ArtIdChoice::Nominal($nm),
prog_pt!(stringify!($f)),
Rc::new(Box::new(
|args1, args2|{
let ($( $lab1 ),*, _) = args1 ;
let ($( $lab2 ),*, _) = args2 ;
$f :: < $( $ty ),* > ( $( $lab1 ),* , $( $lab2 ),* )
})),
( $( $arg1 ),*, () ),
( $( $arg2 ),*, () ),
);
let res = force(&t) ;
(t, res)
}}
;
}
#[macro_export]
macro_rules! cell_call {
( $nm:expr =>> $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
let res = {
$f :: < $( $ty ),* >( $( $arg ),*, )
} ;
let cell = cell($nm, res) ;
cell
}}
;
( $nm:expr =>> $f:ident , $( $lab:ident : $arg:expr ),* ) => {{
let res = {
$f ( $( $arg ),*, )
} ;
let cell = cell($nm, res) ;
cell
}}
}