use std::cell::RefCell;
use std::fmt::{Formatter,Result,Debug};
#[doc(hidden)]
pub use std::rc::Rc;
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) }
}
#[doc(hidden)]
pub fn bump_name_counter() -> usize {
NAME_COUNTER.with(|ctr|{let c = *ctr.borrow(); *ctr.borrow_mut() = c + 1; c})
}
#[doc(hidden)]
#[macro_export]
macro_rules! prog_pt {
($symbol:expr) => {{
ProgPt{
symbol:$symbol,
}
}}
}
#[macro_export]
macro_rules! get {
($art:expr) => {{
force(&($art))
}}
;
($art:expr, $cycle_out:expr) => {{
force_cycle(&($art), Some($cycle_out))
}}
}
#[macro_export]
macro_rules! cell {
( $value:expr ) => {{
cell(name_of_usize(bump_name_counter()), $value)
}}
;
( [ $nm:expr ] ? $value:expr ) => {{
match $nm { Some(n) => cell(n, $value), None => put($value) }
}}
;
( [ $nm:ident ] $value:expr ) => {{
cell(name_of_str(stringify!($nm)), $value)
}}
}
#[macro_export]
macro_rules! thunk {
([ $nmop:expr ] ? $fun:expr ; $( $lab:ident :$arg:expr ),* ) => {{
thunk(
match $nmop {
None => { NameChoice::Eager },
Some(n) => { NameChoice::Nominal(n) }},
prog_pt!(stringify!($fun)),
Rc::new(Box::new(
move |($($lab),*,()),()| $fun ( $($lab),* )
)),
( $( $arg ),*,()),
() )
}}
;
([ $nmop:expr ] ? $fun:expr ; $( $lab:ident :$arg:expr ),* ;; $( $lab2:ident :$arg2:expr ),* ) => {{
thunk(
match $nmop {
None => { NameChoice::Eager },
Some(n) => { NameChoice::Nominal(n) }},
prog_pt!(stringify!($fun)),
Rc::new(Box::new(
move | arg1 , arg2 | {
let ( $( $lab ),*, () ) = arg1 ;
let ( $( $lab2 ),*, () ) = arg2 ;
$fun ( $( $lab ),*, $( $lab2 ),* )
}
)),
( $( $arg ),*, () ),
( $( $arg2 ),*, () )
)
}}
;
( [ $name:ident ] $fun:expr ; $( $lab:ident :$arg:expr ),* ) => {{
thunk!([Some(name_of_str(stringify!($name)))]?
$fun ;
$( $lab:$arg ),*
)
}}
;
( $nm:expr =>> $fun:expr , $( $lab:ident : $arg:expr ),* ) => {{
thunk!([Some($nm)]?
$fun ;
$( $lab:$arg ),*
)
}}
;
( $nm:expr =>> $fun:expr , $( $lab:ident : $arg:expr ),* ;; $( $lab2:ident : $arg2:expr ),* ) => {{
thunk!([Some($nm)]?
$fun ;
$( $lab:$arg ),* ;;
$( $lab2:$arg2 ),*
)
}}
;
[ [ $nmop:expr ] ? $body:expr ] => {{
thunk(
match $nmop {
None => { NameChoice::Eager },
Some(n) => { NameChoice::Nominal(n) }},
prog_pt!(stringify!($body)),
Rc::new(Box::new( move |(),()| { $body } )),
() ,
() )
}}
;
[ [ $name:ident ] $body:expr ] => {{
thunk(
NameChoice::Nominal(name_of_str(stringify!($name))),
prog_pt!(stringify!($fun)),
Rc::new(Box::new( move |(),()| { $body } )),
() ,
() )
}}
;
[ $body:expr ] => {{
thunk![ [Some(name_of_usize(bump_name_counter()))]?
$body ]
}}
}
#[macro_export]
macro_rules! fork {
( $nm:expr ) => {{
name_fork($nm)
}}
}
#[macro_export]
macro_rules! forko {
( $nmop:expr ) => {{
match $nmop {
None => (None,None),
Some(n) => {
let (l,r) = name_fork(n);
(Some(l),Some(r))
}
}
}}
}
#[macro_export]
macro_rules! memo {
( [ $nmop:expr ] ? $fun:expr ; $( $lab:ident :$arg:expr ),* ) => {{
{ let t = thunk!( [$nmop]? $fun ; $( $lab:$arg ),* ); let x = get!(t); (t, x) }
}}
;
( [ $nmop:expr ] ? $fun:expr ; $( $lab:ident :$arg:expr ),* ;; $( $lab2:ident : $arg2:expr ),* ) => {{
{ let t = thunk!( [$nmop]? $fun ; $( $lab:$arg ),* ;; $( $lab2:$arg2 ),* ); let x = get!(t); (t, x) }
}}
;
( $nm:expr =>> $fun:expr , $( $lab:ident : $arg:expr ),* ) => {{
get!(thunk!( [Some($nm)]? $fun ; $( $lab:$arg ),* ))
}}
;
( $nm:expr =>> $fun:expr , $( $lab1:ident : $arg1:expr ),* ;; $( $lab2:ident : $arg2:expr ),* ) => {{
get!(thunk!( [Some($nm)]? $fun ; $( $lab1:$arg1 ),* ;; $( $lab2:$arg2 ),* ))
}}
}
#[macro_export]
#[doc(hidden)]
macro_rules! eager {
( $nm:expr =>> $f:ident :: < $( $ty:ty ),* > , $( $lab:ident : $arg:expr ),* ) => {{
let t = thunk
(NameChoice::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
(NameChoice::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
(NameChoice::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
(NameChoice::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
(NameChoice::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)
}}
;
}
#[doc(hidden)]
#[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
}}
}
#[macro_export]
macro_rules! let_cell {
{ $var:ident = $rhs:expr; $body:expr } => {{ {
let name = name_of_str(stringify!($var));
let value = $rhs;
let $var = cell(name, value); $body }
}};
{ $var1:ident = $rhs1:expr ; $( $var2:ident = $rhs2:expr ),+ ; $body:expr} => {{
let_cell!($var1 = $rhs1;
let_cell!( $( $var2 = $rhs2 ),+ ; $body ))
}};
}
#[macro_export]
macro_rules! let_thunk {
{ $var:ident = $rhs:expr; $body:expr } => {{
let name = name_of_str(stringify!($var));
let $var = thunk!([Some(name)]?{$rhs}); $body
}};
{ $var1:ident = $rhs1:expr ; $( $var2:ident = $rhs2:expr ),+ ; $body:expr} => {{
let_thunk!($var1 = $rhs1;
let_thunk!( $( $var2 = $rhs2 ),+ ; $body ))
}};
}
#[test]
fn test_let_cell_let_thunk_macros() {
use crate::adapton::macros::*;
use crate::adapton::engine::*;
fn demand_graph(a: Art<i32>) -> Art<i32> {
let c : Art<i32> = get!(let_thunk!{f = {
let a = a.clone();
let b : Art<i32> = get!(let_thunk!{g = {let x = get!(a); let_cell!{b = x * x; b}}; g});
let c : Art<i32> = get!(let_thunk!{h = {let x = get!(b); let_cell!{c = if x < 100 { x } else { 100 }; c}}; h});
c}; f});
return c
};
manage::init_dcg();
let _ = demand_graph(cell(name_of_str("a"), 2));
let _ = demand_graph(cell(name_of_str("a"), -2));
let _ = demand_graph(cell(name_of_str("a"), 3));
}
#[macro_export]
macro_rules! let_memo {
{ $var:ident = ( $thkvar1:ident ) = $rhs:expr; $body:expr } => {{
let $thkvar1 = thunk!([$thkvar1]{$rhs});
let $var = get!($thkvar1);
$body
}};
{ $var1:ident = ( $thkvar1:ident ) = $rhs1:expr ; $( $var2:ident = ( $thkvar2:ident ) = $rhs2:expr ),+ ; $body:expr} => {{
let_memo!($var1 = ( $thkvar1 ) = $rhs1;
let_memo!( $( $var2 = ( $thkvar2 ) = $rhs2 ),+ ; $body ))
}};
}
#[test]
fn test_memo_macros() {
use crate::adapton::macros::*;
use crate::adapton::engine::*;
fn demand_graph(a: Art<i32>) -> Art<i32> {
let_memo!{c =(f)= {
let a = a.clone();
let_memo!{b =(g)= {let x = get!(a); let_cell!{b = x * x; b}};
c =(h)= {let x = get!(b); let_cell!{c = if x < 100 { x } else { 100 }; c}};
c}};
c}
}
manage::init_dcg();
let _ = demand_graph(cell(name_of_str("a"), 2));
let _ = demand_graph(cell(name_of_str("a"), -2));
let _ = demand_graph(cell(name_of_str("a"), 3));
}