#[macro_export]
macro_rules! fgi_name {
{ fromast $ast:expr } => { $ast };
{ [] } => { Name::Leaf };
{ name:tt * $($names:tt)+ } => {
Name::Bin(Rc::new(fgi_name![$name]),Rc::new(fgi_name![$($names)+]))
};
{ @@$($s:tt)+ } => { Name::Sym(stringify![$($s)+].to_string())};
{ @$n:expr } => { Name::Num($n) };
{ $($any:tt)* } => { Name::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! fgi_nametm {
{ fromast $ast:expr } => { $ast };
{ ^ $ast:expr } => { $ast };
{ ( $($nmtm:tt)+ ) } => { fgi_nametm![$($nmtm)+] };
{ @@$s:ident } => { NameTm::Name(Name::Sym(stringify![$s].to_string())) };
{ @$n:expr } => { NameTm::Name(Name::Num($n)) };
{ @@ } => { NameTm::WriteScope };
{ # $var:ident : $sort:tt . $($body:tt)+ } => { NameTm::Lam(
stringify![$var].to_string(),
fgi_sort![$sort],
Rc::new(fgi_nametm![$($body)+]),
)};
{ [$($nmfn:tt)+] $par:tt } => { NameTm::App(
Rc::new(fgi_nametm![$($nmfn)+]),
Rc::new(fgi_nametm![$par]),
)};
{ [$($nmfn:tt)+] $par:tt $($pars:tt)+ } => {
fgi_nametm![[fromast NameTm::App(
Rc::new(fgi_nametm![$($nmfn)+]),
Rc::new(fgi_nametm![$par]),
)] $($pars)+]
};
{ $var:ident } => {
NameTm::Var(stringify![$var].to_string())
};
{ ~ $var:ident } => {
NameTm::ValVar(stringify![$var].to_string())
};
{ $n:tt * $m:tt } => {
NameTm::Bin(
Rc::new(fgi_nametm![$n]),
Rc::new(fgi_nametm![$m])
)
};
{ $($nmtms:tt)+ } => { split_star![parse_fgi_name_bin <= $($nmtms)+]};
{ $($any:tt)* } => { NameTm::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! parse_fgi_name_bin {
{ ($($n:tt)+) } => { NameTm::Name(fgi_name![$($n)+]) };
{ ($($n:tt)+)($($m:tt)+) } => { NameTm::Bin(
Rc::new(fgi_nametm![$($n)+]),
Rc::new(fgi_nametm![$($m)+]),
)};
{ ($($n:tt)+)($($m:tt)+) $($more:tt)+ } => { NameTm::Bin(
Rc::new(fgi_nametm![$($n)+]),
Rc::new(parse_fgi_name_bin![($($m)+) $($more)+]),
)};
{ $($any:tt)* } => { NameTm::NoParse(stringify![(, $($any)*)].to_string())};
}
#[macro_export]
macro_rules! fgi_index {
{ fromast $ast:expr } => { $ast };
{ ^ $ast:expr } => { $ast };
{ ? } => { IdxTm::Unknown };
{ nmtm $($nmtm:tt)+ } => { IdxTm::NmTm(fgi_nametm![$($nmtm)+]) };
{ ($($i:tt)+) } => { fgi_index![$($i)+] };
{ {$($nmtm:tt)+} } => { IdxTm::Sing(fgi_nametm![$($nmtm)+]) };
{ @! } => { IdxTm::WriteScope };
{ 0 } => { IdxTm::Empty };
{ $x:tt * $y:tt } => { IdxTm::Bin(
Rc::new(fgi_index![$x]),
Rc::new(fgi_index![$y]),
)};
{ $x:tt % $y:tt } => { IdxTm::Apart(
Rc::new(fgi_index![$x]),
Rc::new(fgi_index![$y]),
)};
{ $x:tt % $y:tt $($more:tt)+ } => {
fgi_index![(fromast IdxTm::Apart(
Rc::new(fgi_index![$x]),
Rc::new(fgi_index![$y]),
)) $($more)+]
};
{ $x:tt U $y:tt } => { IdxTm::Union(
Rc::new(fgi_index![$x]),
Rc::new(fgi_index![$y]),
)};
{ $x:tt U $y:tt $($more:tt)+ } => {
fgi_index![(fromast IdxTm::Union(
Rc::new(fgi_index![$x]),
Rc::new(fgi_index![$y]),
)) $($more)+]
};
{ () } => { IdxTm::Unit };
{ ($i:tt,$j:tt) } => { IdxTm::Pair(
Rc::new(fgi_index![$i]),
Rc::new(fgi_index![$j]),
)};
{ prj1 $($i:tt)+ } => {
IdxTm::Proj1(Rc::new(fgi_index![$i]))
};
{ prj2 $($i:tt)+ } => {
IdxTm::Proj2(Rc::new(fgi_index![$i]))
};
{ # $a:ident : $sort:tt . $($body:tt)+ } => { IdxTm::Lam(
stringify![$a].to_string(),
fgi_sort![$sort],
Rc::new(fgi_index![$($body)+]),
)};
{ {$($i:tt)+} $par:tt } => { IdxTm::App(
Rc::new(fgi_index![$($i)+]),
Rc::new(fgi_index![$par]),
)};
{ {$($i:tt)+} $par:tt $($pars:tt)+ } => {
fgi_index![{fromast IdxTm::App(
Rc::new(fgi_index![$($i)+]),
Rc::new(fgi_index![$par]),
)} $($pars)+]
};
{ [$($m:tt)+] $($par:tt)+ } => { IdxTm::Map(
Rc::new(fgi_nametm![$($m)+]),
Rc::new(fgi_index![$($par)+]),
)};
{ ($($i:tt)+) ^ * $($j:tt)+ } => { IdxTm::FlatMapStar(
Rc::new(fgi_index![$($i)+]),
Rc::new(fgi_index![$($j)+]),
)};
{ ($($i:tt)+) $($par:tt)+ } => { IdxTm::FlatMap(
Rc::new(fgi_index![$($i)+]),
Rc::new(fgi_index![$($par)+]),
)};
{ $var:ident } => {{
let s = stringify![$var].to_string();
assert!(s.len() > 0);
let v:Vec<char> = s.chars().collect();
if v[0].is_lowercase() ||
v[0] == 'X' ||
v[0] == 'Y' ||
v[0] == 'Z'
{
IdxTm::Var(s)
}
else {
IdxTm::Ident(s)
}
}};
{ $($any:tt)* } => { IdxTm::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! fgi_sort {
{ fromast $ast:expr } => { $ast };
{ Nm } => { Sort::Nm };
{ NmSet } => { Sort::NmSet };
{ 1 } => { Sort::Unit };
{ ($g1:tt x $g2:tt) } => { Sort::Prod(
Rc::new(fgi_sort![$g1]),
Rc::new(fgi_sort![$g2]),
)};
{ ($g1:tt x g2:tt x $($more:tt)+) } => { Sort::Prod(
Rc::new(fgi_sort![$g1]),
Rc::new(fgi_sort![($g2 x $($more)+)]),
)};
{ ($g1:tt -> $g2:tt) } => { Sort::NmArrow(
Rc::new(fgi_sort![$g1]),
Rc::new(fgi_sort![$g2]),
)};
{ ($g1:tt -> g2:tt -> $($more:tt)+) } => { Sort::NmArrow(
Rc::new(fgi_sort![$g1]),
Rc::new(fgi_sort![[$g2 -> $($more)+]]),
)};
{ ($g1:tt -> $g2:tt) } => { Sort::IdxArrow(
Rc::new(fgi_sort![$g1]),
Rc::new(fgi_sort![$g2]),
)};
{ ($g1:tt -> g2:tt -> $($more:tt)+) } => { Sort::IdxArrow(
Rc::new(fgi_sort![$g1]),
Rc::new(fgi_sort![{$g2 -> $($more)+}]),
)};
{ ($($sort:tt)+) } => { fgi_sort![$($sort:tt)+] };
{ $($any:tt)* } => { Sort::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! fgi_kind {
{ fromast $ast:expr } => { $ast };
{ ($($kind:tt)+) } => { fgi_kind![$($kind)+] };
{ type } => { Kind::Type };
{ type => $($kinds:tt)+ } => { Kind::TypeParam(
Rc::new(fgi_kind![$($kinds)+])
)};
{ $g:tt => $($kinds:tt)+ } => { Kind::IdxParam(
fgi_sort![$g],
Rc::new(fgi_kind![$($kinds)+]),
)};
{ $($any:tt)* } => { Kind::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! fgi_prop {
{ fromast $ast:expr } => { $ast };
{ ($($prop:tt)+) } => { fgi_prop![$($prop)+] };
{ tt } => { Prop::Tt };
{ $p1:tt and $p2:tt and $($more:tt)+ } => {
fgi_prop![(fromast Prop::Conj(
Rc::new(fgi_prop![$p1]),
Rc::new(fgi_prop![$p2]),
)) and $($more)+ ]
};
{ $p1:tt and $($p2:tt)+ } => { Prop::Conj(
Rc::new(fgi_prop![$p1]),
Rc::new(fgi_prop![$($p2)+]),
)};
{ $i:tt % $j:tt : $($g:tt)+ } => { Prop::Apart(
fgi_index![$i],
fgi_index![$j],
fgi_sort![$($g)+],
)};
{ $i:tt = $j:tt : $($g:tt)+ } => { Prop::Equiv(
fgi_index![$i],
fgi_index![$j],
fgi_sort![$($g)+],
)};
{ $($any:tt)* } => { Prop::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! fgi_effect {
{ fromast $ast:expr } => { $ast };
{ ($($e:tt)+) } => { fgi_effect![$($e)+] };
{ {$($wr:tt)+} } => { split_semi![parse_fgi_eff <= $($wr)+]};
{ 0 } => { fgi_effect![ {0;0} ] };
{ $e1:tt then $e2:tt } => { Effect::Then(
Rc::new(fgi_effect![$e1]),
Rc::new(fgi_effect![$e2]),
)};
{ $e1:tt then $e2:tt $($more:tt)+ } => {
fgi_effect![(fromast Effect::Then(
Rc::new(fgi_effect![$e1]),
Rc::new(fgi_effect![$e2]),
)) $($more)+]
};
{ $($any:tt)* } => { Effect::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! parse_fgi_eff {
{ ($($w:tt)+)($($r:tt)+) } => { Effect::WR(
fgi_index![$($w)+],
fgi_index![$($r)+],
)};
{ $($any:tt)* } => { Effect::NoParse(stringify![(; $($any)*)].to_string())};
}
#[macro_export]
macro_rules! fgi_vtype {
{ fromast $ast:expr } => { $ast };
{ ($($type:tt)+) } => { fgi_vtype![$($type)+] };
{ user($s:ident) } => { Type::Ident(
stringify![$s].to_string()
)};
{ Unit } => { Type::Unit };
{ + $($sum:tt)+ } => { split_plus![parse_fgi_sum <= $($sum)+] };
{ x $($prod:tt)+ } => { split_cross![parse_fgi_prod <= $($prod)+] };
{ Ref[$($i:tt)+] $($t:tt)+ } => { Type::Ref(
fgi_index![$($i)+],
Rc::new(fgi_vtype![$($t)+]),
)};
{ Thk[$($i:tt)+] $($e:tt)+ } => { Type::Thk(
fgi_index![$($i)+],
Rc::new(fgi_ceffect![$($e)+]),
)};
{ Nm[$($i:tt)+] } => { Type::Nm(fgi_index![$($i)+]) };
{ $a:tt [$($i:tt)+] } => { Type::IdxApp(
Rc::new(fgi_vtype![$a]),
fgi_index![$($i)+],
)};
{ $a:tt [$($i:tt)+] $($more:tt)+ } => {
fgi_vtype![(fromast Type::IdxApp(
Rc::new(fgi_vtype![$a]),
fgi_index![$($i)+],
)) $($more)+]
};
{ (Nm->Nm)[$($m:tt)+] } => { Type::NmFn(fgi_nametm![$($m)+]) };
{ forallt $x:ident : $k:tt. $($a:tt)+ } => {Type::TypeFn(
stringify![$x].to_string(),
fgi_kind![$k],
Rc::new(fgi_vtype![$($a)+]),
)};
{ forallt ($x:ident) : $k:tt. $($a:tt)+ } => {
fgi_vtype![forallt $x : $k . $($a)+]
};
{ forallt ($x:ident,$($xs:ident),+):$k:tt.$($a:tt)+ } => { Type::TypeFn(
stringify![$x].to_string(),
fgi_kind![$k],
Rc::new(fgi_vtype![forallt ($($xs),+):$k.$($a)+])
)};
{ foralli $x:ident : $g:tt. $($a:tt)+ } => {Type::IdxFn(
stringify![$x].to_string(),
fgi_sort![$g],
Rc::new(fgi_vtype![$($a)+]),
)};
{ foralli ($x:ident) : $g:tt. $($a:tt)+ } => {
fgi_vtype![foralli $x : $g . $($a)+]
};
{ foralli ($x:ident,$($xs:ident),+):$g:tt.$($a:tt)+ } => { Type::IdxFn(
stringify![$x].to_string(),
fgi_sort![$g],
Rc::new(fgi_vtype![foralli ($($xs),+):$g.$($a)+])
)};
{ rec $a:ident.$($body:tt)+ } => { Type::Rec(
stringify![$a].to_string(),
Rc::new(fgi_vtype![$($body)+]),
)};
{ exists $var:ident : $a:tt . $($b:tt)+ } => {
fgi_vtype![exists $var : $a | tt . $($b)+]
};
{ exists ($var:ident) : $a:tt . $($b:tt)+ } => {
fgi_vtype![exists $var : $a | tt . $($b)+]
};
{ exists $var:ident : $a:tt | $p:tt . $($b:tt)+ } => { Type::Exists(
stringify![$var].to_string(),
Rc::new(fgi_sort![$a]),
fgi_prop![$p],
Rc::new(fgi_vtype![$($b)+]),
)};
{ exists ($var:ident) : $a:tt | $p:tt . $($b:tt)+ } => {
fgi_vtype![exists $var : $a | $p . $($b)+]
};
{ exists ($($vars:ident),+) : $a:tt . $($b:tt)+ } => {
fgi_vtype![exists ($($vars),+) : $a | tt . $($b)+]
};
{ exists ($var:ident,$($vars:ident),+) : $a:tt | $p:tt . $($b:tt)+ } => {
Type::Exists(
stringify![$var].to_string(),
Rc::new(fgi_sort![$a]),
Prop::Tt,
Rc::new(fgi_vtype![exists ($($vars),+):$a|$p.$($b)+])
)
};
{ $a:tt $b:tt } => { Type::TypeApp(
Rc::new(fgi_vtype![$a]),
Rc::new(fgi_vtype![$b]),
)};
{ $a:tt $b:tt $($more:tt)+ } => {
fgi_vtype![(fromast Type::TypeApp(
Rc::new(fgi_vtype![$a]),
Rc::new(fgi_vtype![$b]),
)) $($more)+]
};
{ $a:ident } => {{
let s = stringify![$a].to_string();
assert!(s.len() > 0);
let v:Vec<char> = s.chars().collect();
if v[0].is_uppercase() {
Type::Ident(s)
}
else {
Type::Var(s)
}
}};
{ $($any:tt)* } => { Type::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! parse_fgi_sum {
{ ($($a:tt)+)($($b:tt)+) } => { Type::Sum(
Rc::new(fgi_vtype![$($a)+]),
Rc::new(fgi_vtype![$($b)+]),
)};
{ ($($a:tt)+)$($more:tt)+ } => { Type::Sum(
Rc::new(fgi_vtype![$($a)+]),
Rc::new(parse_fgi_sum![$($more)+]),
)};
{ $($any:tt)* } => { Type::NoParse(stringify![(+ $($any)*)].to_string())};
}
#[macro_export]
macro_rules! parse_fgi_prod {
{ ($($a:tt)+)($($b:tt)+) } => { Type::Prod(
Rc::new(fgi_vtype![$($a)+]),
Rc::new(fgi_vtype![$($b)+]),
)};
{ ($($a:tt)+)$($more:tt)+ } => { Type::Prod(
Rc::new(fgi_vtype![$($a)+]),
Rc::new(parse_fgi_prod![$($more)+]),
)};
{ $($any:tt)* } => { Type::NoParse(stringify![(x $($any)*)].to_string())};
}
#[macro_export]
macro_rules! fgi_ctype {
{ fromast $ast:expr } => { $ast };
{ ($($c:tt)+) } => { fgi_ctype![$($c)+] };
{ F $($a:tt)+ } => { CType::Lift(fgi_vtype![$($a)+]) };
{ $($arrow:tt)+ } => { split_arrow![parse_fgi_arrow <= $($arrow)+] };
{ $($any:tt)* } => { CType::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! parse_fgi_arrow {
{ ($($a:tt)+)($($e:tt)+)$($more:tt)* } => { CType::Arrow(
fgi_vtype![$($a)+],
Rc::new(parse_fgi_earrow![($($e)+)$($more)*]),
)};
{ $($any:tt)* } => { CType::NoParse(stringify![(-> $($any)*)].to_string())};
}
#[macro_export]
macro_rules! fgi_ceffect {
{ fromast $ast:expr } => { $ast };
{ ($($e:tt)+) } => { fgi_ceffect![$($e)+] };
{ forallt ($a:ident):$k:tt.$($e:tt)+ } => {
fgi_ceffect![forallt $a:$k.$($e)+]
};
{ forallt $a:ident:$k:tt.$($e:tt)+ } => { CEffect::ForallType(
stringify![$a].to_string(),
fgi_kind![$k],
Rc::new(fgi_ceffect![$($e)+]),
)};
{ forallt ($a:ident,$($vars:ident),+):$k:tt.$($e:tt)+ } => {
CEffect::ForallType(
stringify![$a].to_string(),
fgi_kind![$k],
Rc::new(fgi_ceffect![forallt ($($vars),+):$k.$($e)+]),
)
};
{ foralli ($a:ident):$g:tt|$p:tt.$($e:tt)+ } => {
fgi_ceffect![foralli $a:$g|$p.$($e)+]
};
{ foralli $a:ident:$g:tt|$p:tt.$($e:tt)+ } => { CEffect::ForallIdx(
stringify![$a].to_string(),
fgi_sort![$g],
fgi_prop![$p],
Rc::new(fgi_ceffect![$($e)+]),
)};
{ foralli ($a:ident,$($vars:ident),+):$g:tt|$p:tt.$($e:tt)+ } => {
CEffect::ForallIdx(
stringify![$a].to_string(),
fgi_sort![$g],
Prop::Tt,
Rc::new(fgi_ceffect![foralli ($($vars),+):$g|$p.$($e)+]),
)
};
{ foralli $a:ident:$g:tt.$($e:tt)+ } => {
fgi_ceffect![foralli $a:$g|tt.$($e)+]
};
{ foralli ($a:ident):$g:tt.$($e:tt)+ } => {
fgi_ceffect![foralli $a:$g|tt.$($e)+]
};
{ foralli ($a:ident,$($vars:ident),+):$g:tt.$($e:tt)+ } => {
fgi_ceffect![foralli ($a,$($vars),+):$g|tt.$($e)+]
};
{ $($arr:tt)+ } => { split_arrow![parse_fgi_earrow <= $($arr)+] };
{ $($any:tt)* } => { CEffect::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! parse_fgi_earrow {
{ ($e:tt $($c:tt)+) } => { CEffect::Cons(
fgi_ctype![$($c)+],
fgi_effect![$e],
)};
{ ($e:tt $($a:tt)+)($($c:tt)+) $($more:tt)* } => { CEffect::Cons(
parse_fgi_arrow![($($a)+)($($c)+) $($more)*],
fgi_effect![$e],
)};
{ $($any:tt)* } => { CEffect::NoParse(stringify![(-> $($any)*)].to_string())};
}
#[macro_export]
macro_rules! fgi_rtval {
{ inj1 $($v:tt)+ } => {
RtVal::Inj1( Rc::new( fgi_rtval!( $($v)+ ) ) )
};
{ inj2 $($v:tt)+ } => {
RtVal::Inj2( Rc::new( fgi_rtval!( $($v)+ ) ) )
};
{ ($($tup:tt)*) } => {
split_comma![parse_fgi_rt_tuple <= $($tup)*]
};
{ host $v:expr } => {
fungi_lang::hostobj::rtval_of_obj( $v )
};
{ bool $v:expr } => {
RtVal::Bool( $v )
};
{ usize $v:expr } => {
RtVal::Nat( $v )
};
{ name $v:expr } => {
RtVal::Name( $v )
};
{ string $v:expr } => {
RtVal::String( $v )
};
}
#[macro_export]
macro_rules! parse_fgi_rt_tuple {
{ } => { RtVal::Unit };
{ ($($v:tt)+) } => { fgi_rtval![$($v)+] };
{ ($($v:tt)+) $($more:tt)+ } => { RtVal::Pair(
Rc::new(fgi_rtval![$($v)+]),
Rc::new(parse_fgi_rt_tuple![$($more)+]),
)};
{ $($any:tt)* } => { RtVal::NoParse(stringify![(, $($any)*)].to_string())};
}
#[macro_export]
macro_rules! fgi_val {
{ fromast $ast:expr } => { $ast };
{ ^ $ast:expr } => { $ast };
{ $v:tt : $($a:tt)+} => { Val::Anno(
Rc::new(fgi_val![$v]),
fgi_vtype![$($a)+],
)};
{ thunk $($e:tt)+ } => { Val::ThunkAnon(Rc::new(fgi_exp![$($e)+])) };
{ ($($tup:tt)*) } => { split_comma![parse_fgi_tuple <= $($tup)*] };
{ inj1 $($v:tt)+ } => { Val::Inj1(Rc::new(fgi_val![$($v)+])) };
{ inj2 $($v:tt)+ } => { Val::Inj2(Rc::new(fgi_val![$($v)+])) };
{ roll $($v:tt)+ } => { Val::Roll(Rc::new(fgi_val![$($v)+])) };
{ pack ($($is:tt)+) $($v:tt)+ } => {
split_comma![parse_fgi_pack_multi (($($v)+)) <= $($is)+]
};
{ pack $i:tt $($v:tt)+ } => { Val::Pack(
fgi_index![ $i ],
Rc::new(fgi_val![$($v)+]),
)};
{ name $($n:tt)+ } => { Val::Name(fgi_name![$($n)+]) };
{ nmfn $($m:tt)+ } => { Val::NameFn(fgi_nametm![$($m)+]) };
{ true } => { Val::Bool(true) };
{ false } => { Val::Bool(false) };
{ @@$($s:tt)+ } => { Val::Name(Name::Sym(stringify![$($s)+].to_string())) };
{ @$n:expr } => { Val::Name(Name::Num($n)) };
{ str($($s:tt)*) } => { Val::Str(stringify![$($s)*].to_string()) };
{ $x:ident } => { Val::Var(stringify![$x].to_string()) };
{ $n:expr } => { Val::Nat($n) };
{ $($any:tt)* } => { Val::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! parse_fgi_tuple {
{ } => { Val::Unit };
{ ($($v:tt)+) } => { fgi_val![$($v)+] };
{ ($($v:tt)+) $($more:tt)+ } => { Val::Pair(
Rc::new(fgi_val![$($v)+]),
Rc::new(parse_fgi_tuple![$($more)+]),
)};
{ $($any:tt)* } => { Val::NoParse(stringify![(, $($any)*)].to_string())};
}
#[macro_export]
macro_rules! parse_fgi_pack_multi {
{($($v:tt)+) ($($i:tt)+) } => { Val::Pack(
fgi_index![$($i)+],
Rc::new(fgi_val![$($v)+]),
)};
{($($v:tt)+) ($($i:tt)+) $($more:tt)+ } => { Val::Pack(
fgi_index![$($i)+],
Rc::new(parse_fgi_pack_multi![($($v)+) $($more)+]),
)};
}
#[macro_export]
macro_rules! fgi_host_exp {
{ ( $args:expr, $argi:expr, $arity:expr ) { $($e:tt)+ } } => {
fgi_host_exp!{ ( $args, $argi, $arity ) $($e)+ }
};
{ ( $args:expr, $argi:expr, $arity:expr ) # $x:ident . $($e:tt)+ } => {
let i = $argi; $argi += 1;
let $x : RtVal = ( $args[ i ] ).clone();
fgi_host_exp!{ ( $args, $argi, $arity ) $($e)+ }
};
{ ( $args:expr, $argi:expr, $arity:expr ) # ( mut $x:ident : $ty:ty ) . $($e:tt)+ } => {
let i = $argi; $argi += 1;
let mut $x : $ty = fungi_lang::hostobj::obj_of_rtval( & $args[ i ] ).unwrap();
fgi_host_exp!{ ( $args, $argi, $arity ) $($e)+ }
};
{ ( $args:expr, $argi:expr, $arity:expr ) # ( $x:ident : $ty:ty ) . $($e:tt)+ } => {
let i = $argi; $argi += 1;
let $x : $ty = fungi_lang::hostobj::obj_of_rtval( & $args[ i ] ).unwrap();
fgi_host_exp!{ ( $args, $argi, $arity ) $($e)+ }
};
{ ( $args:expr, $argi:expr, $arity:expr ) $($e:tt)+ } => {
assert_eq!( $argi, $arity );
$($e)+
}
}
#[macro_export]
macro_rules! fgi_exp {
{ fromast $ast:expr } => { $ast };
{ ^ $ast:expr } => { $ast };
{ unsafe ($arity:expr) $rustfn:path } => {
Exp::HostFn(HostEvalFn{
path:stringify![$rustfn].to_string(),
arity:$arity,
eval:Rc::new($rustfn),
})
};
{ hostfn ($arity:expr) $($host_e:tt)+ } => {
Exp::HostFn(HostEvalFn{
path:stringify![$($host_e)+].to_string(),
arity:$arity,
eval:Rc::new({
use $crate::dynamics::{RtVal,ExpTerm,ret};
|args:Vec<RtVal>| -> ExpTerm {
let mut argi = 0;
let retv = {
fgi_host_exp!{ ( args, argi, $arity ) $($host_e)+ }
};
ret( retv )
}
}),
})
};
{ # [ doc = $doc:tt ] $($d:tt)* } => {
Exp::Doc( { $crate::util::string_of_rust_raw_str(stringify![$doc]) },
Rc::new( fgi_exp![ $($d)* ] ))
};
{ open $path:path ; $($e:tt)* } => {
Exp::UseAll(
UseAllModule{
module:{ use $path as x ; x::fgi_module () },
path:stringify![$path].to_string(),
},
Rc::new( fgi_exp![ $($e)* ] )
)
};
{ decls $d:tt ; $($e:tt)+ } => { Exp::Decls(
Rc::new(fgi_decls![$d]),
Rc::new(fgi_exp![$($e)+])
)
};
{ decls $d:tt $($e:tt)+ } => { Exp::Decls(
Rc::new(fgi_decls![$d]),
Rc::new(fgi_exp![$($e)+])
)
};
{ $e:tt : $($c:tt)+ } => { Exp::AnnoC(
Rc::new(fgi_exp![$e]),
fgi_ctype![$($c)+],
)};
{ $e:tt : $($c:tt)+ } => { Exp::AnnoE(
Rc::new(fgi_exp![$e]),
fgi_ceffect![$($c)+],
)};
{ {$($e:tt)+} } => { fgi_exp![$($e)+] };
{ ws $v:tt $($e:tt)+ } => { Exp::WriteScope(
fgi_val![$v],
Rc::new(fgi_exp![$($e)+]),
)};
{ ret $($v:tt)+ } => { Exp::Ret(fgi_val![$($v)+]) };
{ #$x:ident.$($e:tt)+ } => { Exp::Lam(
stringify![$x].to_string(),
Rc::new(fgi_exp![$($e)+]),
)};
{ fix $x:ident.$($e:tt)+ } => { Exp::Fix(
stringify![$x].to_string(),
Rc::new(fgi_exp![$($e)+]),
)};
{ fix ^ $x:ident.$($e:tt)+ } => { Exp::Fix(
($x).clone(),
Rc::new(fgi_exp![$($e)+]),
)};
{ unroll match $v:tt $($more:tt)+ } => {
Exp::Unroll(fgi_val![$v],
"sugar_match_unroll".to_string(),
Rc::new(fgi_exp![
match sugar_match_unroll $($more)+
]))
};
{ unroll $v:tt $x:ident.$($e:tt)+ } => {
Exp::Unroll(
fgi_val![$v],
stringify![$x].to_string(),
Rc::new(fgi_exp![$($e)+]))
};
{ unpack ($idx:ident,$($idxs:ident),+) $var:ident = $val:tt $($exp:tt)+ } => {
Exp::Unpack(
stringify![$idx].to_string(),
"sugar_unpack_multi".to_string(),
fgi_val![$val],
Rc::new(fgi_exp![unpack ($($idxs),+) $var = sugar_unpack_multi
$($exp)+]),
)
};
{ unpack ($idx:ident) $var:ident = $val:tt $($exp:tt)+ } => {
Exp::Unpack(
stringify![$idx].to_string(),
stringify![$var].to_string(),
fgi_val![$val],
Rc::new(fgi_exp![$($exp)+]),
)
};
{ unpack $idxs:tt $var:ident = {$($e1:tt)+} $($e2:tt)+ } => {
fgi_exp![
let sugar_unpack_exp = {$($e1)+}
unpack $idxs $var = (sugar_unpack_exp)
$($e2)+
]
};
{ {$($e:tt)+} {!$ref:ident} $($more:tt)* } => {
fgi_exp![{fromast Exp::Let(
format!("{}{}",
stringify![app_get_sugar_],
stringify![$ref],
),
Rc::new(Exp::Get(Val::Var(stringify![$ref].to_string()))),
Rc::new(Exp::App(
Rc::new(fgi_exp![$($e)+]),
Val::Var(format!("{}{}",
stringify![app_get_sugar_],
stringify![$ref],
)),
)),
)} $($more)*]
};
{ {$($e:tt)+} [$($i:tt)+] } => { Exp::IdxApp(
Rc::new(fgi_exp![$($e)+]),
fgi_index![$($i)+],
)};
{ {$($e:tt)+} [$($i:tt)+] $($more:tt)+ } => {
fgi_exp![{fromast Exp::IdxApp(
Rc::new(fgi_exp![$($e)+]),
fgi_index![$($i)+],
)} $($more)+]
};
{ {$($e:tt)+} $v:tt } => { Exp::App(
Rc::new(fgi_exp![$($e)+]),
fgi_val![$v],
)};
{ {$($e:tt)+} $v:tt $($more:tt)+ } => {
fgi_exp![{fromast Exp::App(
Rc::new(fgi_exp![$($e)+]),
fgi_val![$v],
)} $($more)+]
};
{ type $t:ident = $a:tt $($e:tt)+ }=>{Exp::DefType(
stringify![$t].to_string(),
fgi_vtype![$a],
Rc::new(fgi_exp![$($e)+]),
)};
{ let $x:ident = $e1:tt $($e2:tt)+ } => { Exp::Let(
stringify![$x].to_string(),
Rc::new(fgi_exp![$e1]),
Rc::new(fgi_exp![$($e2)+]),
)};
{ let $x:ident : $a:tt = $e1:tt $($e2:tt)+ } => { Exp::Let(
stringify![$x].to_string(),
Rc::new(Exp::AnnoC(
Rc::new(fgi_exp![$e1]),
fgi_ctype![F $a]
)),
Rc::new(fgi_exp![$($e2)+]),
)};
{ let rec $x:ident : $a:tt = $e1:tt $($e2:tt)+ } => { Exp::Let(
stringify![$x].to_string(),
Rc::new(Exp::AnnoC(
Rc::new(Exp::Ret(Val::ThunkAnon(
Rc::new(Exp::Fix(stringify![$x].to_string(),
Rc::new(fgi_exp![$e1])))))
),
fgi_ctype![F $a]
)),
Rc::new(fgi_exp![$($e2)+]),
)};
{ thk $v:tt $($e:tt)+ } => { Exp::Thunk(
fgi_val![$v],
Rc::new(fgi_exp![$($e)+]),
)};
{ ref 0 $($v:tt)+ } => {
Exp::RefAnon(
fgi_val![$($v)+]
)
};
{ ref { $($e1:tt)+ } $($v2:tt)+ } => {
Exp::Let("ref_name_sugar".to_string(),
Rc::new(fgi_exp![ $($e1)+ ]),
Rc::new(Exp::Ref(
Val::Var("ref_name_sugar".to_string()),
fgi_val![$($v2)+]
))
)
};
{ ref $v1:tt $($v2:tt)+ } => { Exp::Ref(
fgi_val![$v1],
fgi_val![$($v2)+],
)};
{ force $($v:tt)+ } => { Exp::Force( fgi_val![$($v)+])};
{ refthunk $($v:tt)+ } => { Exp::PrimApp( PrimApp::RefThunk(fgi_val![$($v)+])) };
{ get $($v:tt)+ } => { Exp::Get( fgi_val![$($v)+])};
{ let ($($vars:tt)+) = {$($e1:tt)+} $($e2:tt)+ } => {
fgi_exp![
let let_split_sugar = {$($e1)+}
let ($($vars)+) = let_split_sugar
$($e2)+
]
};
{ let ($($vars:tt)+) = $v:tt $($e:tt)+ } => {
split_comma![parse_fgi_split ($v {$($e)+}) <= $($vars)+]
};
{ match $v:tt {$x1:ident=>$e1:tt $x2:ident=>$e2:tt} } => { Exp::Case(
fgi_val![$v],
stringify![$x1].to_string(),
Rc::new(fgi_exp![$e1]),
stringify![$x2].to_string(),
Rc::new(fgi_exp![$e2]),
)};
{ match $v:tt {$x1:ident=>$e1:tt $x2:ident=>$e2:tt $($more:tt)+} } => {
Exp::Case(
fgi_val![$v],
stringify![$x1].to_string(),
Rc::new(fgi_exp![$e1]),
"sugar_match_snd".to_string(),
Rc::new(fgi_exp![
match sugar_match_snd {
$x2=>$e2 $($more)+
}
]),
)
};
{ memo{$($e1:tt)+}{$($e2:tt)+} } => {
fgi_exp![
let memo_name_sugar = {$($e1)+}
memo(memo_name_sugar){$($e2)+}
]
};
{ memo($($v:tt)+){$($e:tt)+} } => {
fgi_exp![
let memo_keyword_sugar = { thk ($($v)+) $($e)+ }
refthunk memo_keyword_sugar
]
};
{ match $v:tt {$x1:ident=>$e1:tt $x2:ident=>$e2:tt} } => { Exp::Case(
fgi_val![$v],
stringify![$x1].to_string(),
Rc::new(fgi_exp![$e1]),
stringify![$x2].to_string(),
Rc::new(fgi_exp![$e2]),
)};
{ if ( $($v:tt)+ ) { $($e1:tt)+ } else { $($e2:tt)+ } } => {
Exp::IfThenElse(
fgi_val![$($v)+],
Rc::new(fgi_exp![$($e1)+]),
Rc::new(fgi_exp![$($e2)+])
)
};
{ if { $($e:tt)+ } { $($e1:tt)+ } else { $($e2:tt)+ } } => {
Exp::Let("sugar_if_scrutinee".to_string(),
Rc::new(fgi_exp![$($e)+]),
Rc::new(Exp::IfThenElse(
Val::Var("sugar_if_scrutinee".to_string()),
Rc::new(fgi_exp![$($e1)+]),
Rc::new(fgi_exp![$($e2)+])
)))
};
{ [$($v1:tt)+] $v2:tt } => { Exp::NameFnApp(
fgi_val![$($v1)+],
fgi_val![$v2],
)};
{ [$($v1:tt)+] $v2:tt $($more:tt)+ } => {
fgi_exp![
let sugar_nmfn_exp = {[$($v1)+] $v2}
[sugar_nmfn_exp] $($more)+
]
};
{ $v1:tt, $v2:tt } => {
Exp::PrimApp(PrimApp::NameBin( fgi_val!($v1),
fgi_val!($v2) ))
};
{ $v1:tt, $($more:tt)+ } => {
fgi_exp![
let sugar_name_pair = {fromast fgi_exp![$($more)+]}
ret $v1, sugar_name_pair
]
};
{ $v1:tt < $v2:tt } => { Exp::PrimApp(PrimApp::NatLt(
fgi_val![$v1],
fgi_val![$v2],
))};
{ $v1:tt == $v2:tt } => { Exp::PrimApp(PrimApp::NatEq(
fgi_val![$v1],
fgi_val![$v2],
))};
{ $v1:tt <= $v2:tt } => { Exp::PrimApp(PrimApp::NatLeq(
fgi_val![$v1],
fgi_val![$v2],
))};
{ $v1:tt + $v2:tt } => { Exp::PrimApp(PrimApp::NatPlus(
fgi_val![$v1],
fgi_val![$v2],
))};
{ unimplemented } => { Exp::Unimp };
{ label [$($n:tt)+]($($s:tt)+) $($e:tt)+ } => { Exp::DebugLabel(
Some(fgi_name![$($n)+]),
Some(stringify![$($s)+].to_string()),
Rc::new(fgi_exp![$($e)+]),
)};
{ label ($($s:tt)+)[$($n:tt)+] $($e:tt)+ } => { Exp::DebugLabel(
Some(fgi_name![$($n)+]),
Some(stringify![$($s)+].to_string()),
Rc::new(fgi_exp![$($e)+]),
)};
{ label ($($s:tt)+) $($e:tt)+ } => { Exp::DebugLabel(
None,
Some(stringify![$($s)+].to_string()),
Rc::new(fgi_exp![$($e)+]),
)};
{ label [$($n:tt)+] $($e:tt)+ } => { Exp::DebugLabel(
Some(fgi_name![$($n)+]),
None,
Rc::new(fgi_exp![$($e)+]),
)};
{ $($any:tt)* } => { Exp::NoParse(stringify![$($any)*].to_string())};
}
#[macro_export]
macro_rules! parse_fgi_split {
{ $v:tt $e:tt ($x1:ident)($x2:ident) } => { Exp::Split(
fgi_val![$v],
stringify![$x1].to_string(),
stringify![$x2].to_string(),
Rc::new(fgi_exp![$e]),
)};
{ $v:tt $e:tt ($x1:ident)($x2:ident) $($more:tt)+ } => {
Exp::Split(
fgi_val![$v],
stringify![$x1].to_string(),
"sugar_split_snd".to_string(),
Rc::new(parse_fgi_split![sugar_split_snd $e ($x2) $($more)+]),
)
};
{ $($any:tt)* } => { Exp::NoParse(stringify![(, $($any)*)].to_string())};
}
#[macro_export]
macro_rules! fgi_mod {
{ hostuse { $($deps:tt)+ } $($decls:tt)+ } => {
use {$($deps)+};
use std::rc::Rc;
use $crate::shared::Shared;
use $crate::ast::*;
pub fn fgi_module () -> Shared<Module> {
Shared::new( fgi_module![ $($decls)+
] )
}
};
{ $($decls:tt)+ } => {
use std::rc::Rc;
use $crate::shared::Shared;
use $crate::ast::*;
pub fn fgi_module () -> Shared<Module> {
drop(Rc::new(())); Shared::new( fgi_module![ $($decls)+
] )
}
};
}
#[macro_export]
macro_rules! fgi_inner_mod {
{ ( $name:ident ) $($decls:tt)+ } => {
mod $name {
use std::rc::Rc;
use $crate::shared::Shared;
use $crate::ast::*;
pub fn fgi_module () -> Shared<Module> {
Rc::new( fgi_module![ $($decls)+ ] )
}
}
};
{ pub ( $name:ident ) $($decls:tt)+ } => {
pub mod $name {
use std::rc::Rc;
use $crate::shared::Shared;
use $crate::ast::*;
pub fn fgi_module () -> Shared<Module> {
Rc::new( fgi_module![ $($decls)+ ] )
}
}
};
}
#[macro_export]
macro_rules! fgi_module {
{ $($decls:tt)+ } => {
Module {
path: module_path!().to_string(),
body: stringify![ $($decls)+].to_string(),
decls: fgi_decls![ $($decls)+ ],
}
}
}
#[macro_export]
macro_rules! fgi_decls {
{ fromast $ast:expr } => {
unimplemented!()
};
{ # [ doc = $doc:tt ] $($d:tt)* } => {
Decls::Doc( stringify![$doc].to_string(),
Rc::new( fgi_decls![ $($d)* ] ))
};
{ open $path:path ; $($d:tt)* } => {
Decls::UseAll(
UseAllModule{
module: { use $path as x ; x::fgi_module () },
path:stringify![$path].to_string(),
},
Rc::new(fgi_decls![ $($d)* ])
)
};
{ idxtm $x:ident = ( $($i:tt)+ ) $($d:tt)* } => {
Decls::IdxTm( stringify![$x].to_string(),
fgi_index![ $($i)+ ],
Rc::new( fgi_decls![ $($d)* ] ) )
};
{ nmtm $x:ident = ( $($N:tt)+ ) $($d:tt)* } => {
Decls::NmTm( stringify![$x].to_string(),
fgi_nametm![ $($N)+ ],
Rc::new( fgi_decls![ $($d)* ] ) )
};
{ type $t:ident = ( $($a:tt)+ ) $($d:tt)* } => {
Decls::Type( stringify![$t].to_string(),
fgi_vtype![ $($a)+ ],
Rc::new( fgi_decls![ $($d)* ] ) )
};
{ type $t:ident ; $($d:tt)* } => {
Decls::Type( stringify![$t].to_string(),
Type::Abstract( stringify![$t].to_string() ),
Rc::new( fgi_decls![ $($d)* ] ) )
};
{ val $x:ident : ( $($a:tt)+ ) = ( $($v:tt)+ ) $($d:tt)* } => {
Decls::Val( stringify![$x].to_string(),
Some(fgi_vtype![ $($a)+ ]),
fgi_val![ $($v)+ ],
Rc::new( fgi_decls![ $($d)* ] ) )
};
{ val $x:ident = ( $($v:tt)+ ) $($d:tt)* } => {
Decls::Val( stringify![$x].to_string(),
Some(fgi_vtype![ $($a)+ ]),
None,
Rc::new( fgi_decls![ $($d)* ] ) )
};
{ fn $f:ident : ( $($a:tt)+ ) { $($e:tt)+ } $($d:tt)* } => {
fgi_decls![ $f : ( $($a)+ ) = { $($e)+ } $($d)* ]
};
{ fn $f:ident : ( $($a:tt)+ ) = { $($e:tt)+ } $($d:tt)* } => {
Decls::Fn( stringify![$f].to_string(),
fgi_vtype![ $($a)+ ],
fgi_exp![ $($e)+ ],
Rc::new( fgi_decls![ $($d)* ] ) )
};
{ ; $($d:tt)* } => {
fgi_decls![ $($d)* ] };
{ } => {
Decls::End
};
{ ^^ $e:expr } => {
{ drop($e); Decls::End }
};
{ { $($d:tt)+ } } => {
fgi_decls![$($d)+]
};
{ $($any:tt)* } => { Decls::NoParse(stringify![ $($any)* ].to_string())};
}
#[macro_export]
macro_rules! split_cross {
{$fun:ident <= $($item:tt)*} => {
split_cross![$fun () () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) <= $($item:tt)*} => {
split_cross![$fun ($($first)*) () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) <= $($item:tt)*} => {
split_cross![$fun ($($first)*) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= x $($item:tt)+} => {
split_cross![$fun ($($first)* ($($current)*)) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= x } => {
$fun![$($first)* ($($current)*)]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= $next:tt $($item:tt)*} => {
split_cross![$fun ($($first)*) ($($every)*) ($($current)* $next) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= } => {
$fun![$($first)* ($($current)*)]
};
{$fun:ident ($($first:tt)*) () () <= } => {
$fun![$($first)*]
};
}
#[macro_export]
macro_rules! split_plus {
{$fun:ident <= $($item:tt)*} => {
split_plus![$fun () () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) <= $($item:tt)*} => {
split_plus![$fun ($($first)*) () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) <= $($item:tt)*} => {
split_plus![$fun ($($first)*) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= + $($item:tt)+} => {
split_plus![$fun ($($first)* ($($current)*)) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= + } => {
$fun![$($first)* ($($current)*)]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= $next:tt $($item:tt)*} => {
split_plus![$fun ($($first)*) ($($every)*) ($($current)* $next) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= } => {
$fun![$($first)* ($($current)*)]
};
{$fun:ident ($($first:tt)*) () () <= } => {
$fun![$($first)*]
};
}
#[macro_export]
macro_rules! split_arrow {
{$fun:ident <= $($item:tt)*} => {
split_arrow![$fun () () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) <= $($item:tt)*} => {
split_arrow![$fun ($($first)*) () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) <= $($item:tt)*} => {
split_arrow![$fun ($($first)*) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= -> $($item:tt)+} => {
split_arrow![$fun ($($first)* ($($current)*)) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= $next:tt $($item:tt)*} => {
split_arrow![$fun ($($first)*) ($($every)*) ($($current)* $next) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= } => {
$fun![$($first)* ($($current)*)]
};
{$fun:ident ($($first:tt)*) () () <= } => {
$fun![$($first)*]
};
}
#[macro_export]
macro_rules! split_semi {
{$fun:ident <= $($item:tt)*} => {
split_semi![$fun () () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) <= $($item:tt)*} => {
split_semi![$fun ($($first)*) () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) <= $($item:tt)*} => {
split_semi![$fun ($($first)*) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= ; $($item:tt)+} => {
split_semi![$fun ($($first)* ($($current)*)) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= ; } => {
$fun![$($first)* ($($current)*)]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= $next:tt $($item:tt)*} => {
split_semi![$fun ($($first)*) ($($every)*) ($($current)* $next) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= } => {
$fun![$($first)* ($($current)*)]
};
{$fun:ident ($($first:tt)*) () () <= } => {
$fun![$($first)*]
};
}
#[macro_export]
macro_rules! split_comma {
{$fun:ident <= $($item:tt)*} => {
split_comma![$fun () () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) <= $($item:tt)*} => {
split_comma![$fun ($($first)*) () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) <= $($item:tt)*} => {
split_comma![$fun ($($first)*) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= , $($item:tt)+} => {
split_comma![$fun ($($first)* ($($current)*)) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= , } => {
$fun![$($first)* ($($current)*)]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= $next:tt $($item:tt)*} => {
split_comma![$fun ($($first)*) ($($every)*) ($($current)* $next) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= } => {
$fun![$($first)* ($($current)*)]
};
{$fun:ident ($($first:tt)*) () () <= } => {
$fun![$($first)*]
};
}
#[macro_export]
macro_rules! split_star {
{$fun:ident <= $($item:tt)*} => {
split_star![$fun () () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) <= $($item:tt)*} => {
split_star![$fun ($($first)*) () () <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) <= $($item:tt)*} => {
split_star![$fun ($($first)*) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= * $($item:tt)+} => {
split_star![$fun ($($first)* ($($current)*)) ($($every)*) ($($every)*) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= * } => {
$fun![$($first)* ($($current)*)]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)*) <= $next:tt $($item:tt)*} => {
split_star![$fun ($($first)*) ($($every)*) ($($current)* $next) <= $($item)*]
};
{$fun:ident ($($first:tt)*) ($($every:tt)*) ($($current:tt)+) <= } => {
$fun![$($first)* ($($current)*)]
};
{$fun:ident ($($first:tt)*) () () <= } => {
$fun![$($first)*]
};
}