use std::rc::Rc;
pub type Var = String;
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum Name {
Leaf,
Sym(String),
Num(usize),
Bin(NameRec, NameRec),
NoParse(String),
}
pub type NameRec = Rc<Name>;
#[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())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum NameTm {
Var(Var),
Name(Name),
Bin(NameTmRec, NameTmRec),
Lam(Var, Sort, NameTmRec),
App(NameTmRec, NameTmRec),
NoParse(String),
}
pub type NameTmRec = Rc<NameTm>;
#[macro_export]
macro_rules! fgi_nametm {
{ fromast $ast:expr } => { $ast };
{ [$($nmtm:tt)+] } => { fgi_nametm![$($nmtm)+] };
{ @$($nm:tt)+ } => { NameTm::Name(fgi_name![@$($nm)+]) };
{ # $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()) };
{ $($nmtms:tt)+ } => { split_comma![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())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum IdxTm {
Var(Var),
Sing(NameTm),
Empty,
Disj(IdxTmRec, IdxTmRec),
Union(IdxTmRec, IdxTmRec),
Unit,
Pair(IdxTmRec, IdxTmRec),
Proj1(IdxTmRec),
Proj2(IdxTmRec),
Lam(Var, Sort, IdxTmRec),
App(IdxTmRec, IdxTmRec),
Map(NameTmRec, IdxTmRec),
FlatMap(IdxTmRec, IdxTmRec),
Star(IdxTmRec, IdxTmRec),
NoParse(String),
}
pub type IdxTmRec = Rc<IdxTm>;
#[macro_export]
macro_rules! fgi_index {
{ fromast $ast:expr } => { $ast };
{ ($($i:tt)+) } => { fgi_index![$($i)+] };
{ {$($nmtm:tt)+} } => { IdxTm::Sing(fgi_nametm![$($nmtm)+])};
{ 0 } => { IdxTm::Empty };
{ $x:tt % $y:tt } => { IdxTm::Disj(
Rc::new(fgi_index![$x]),
Rc::new(fgi_index![$y]),
)};
{ $x:tt % $y:tt $($more:tt)+ } => {
fgi_index![(fromast IdxTm::Disj(
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::Star(
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 } => { IdxTm::Var(stringify![$var].to_string()) };
{ $($any:tt)* } => { IdxTm::NoParse(stringify![$($any)*].to_string())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum Sort {
Nm,
NmSet,
NmArrow(SortRec,SortRec),
IdxArrow(SortRec,SortRec),
Unit,
Prod(SortRec,SortRec),
NoParse(String),
}
pub type SortRec = Rc<Sort>;
#[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())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum Kind {
Type,
TypeParam(KindRec),
IdxParam(Sort, KindRec),
NoParse(String),
}
pub type KindRec = Rc<Kind>;
#[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())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum Prop {
Tt,
Equiv(IdxTm, IdxTm, Sort),
Disj(IdxTm, IdxTm, Sort),
Conj(PropRec, PropRec),
NoParse(String),
}
pub type PropRec = Rc<Prop>;
#[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::Disj(
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())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum Effect {
WR(IdxTm, IdxTm),
Then(EffectRec, EffectRec),
NoParse(String),
}
pub type EffectRec = Rc<Effect>;
#[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())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum TypeCons {
D,
Bool,
Nat,
String,
Seq,
User(String),
NoParse(String),
}
#[macro_export]
macro_rules! fgi_tcons {
{ D } => { TypeCons::D };
{ Bool } => { TypeCons::Bool };
{ Nat } => { TypeCons::Nat };
{ String } => { TypeCons::String };
{ Seq } => { TypeCons::Seq };
{ $s:ident } => { TypeCons::User(stringify![$s].to_string()) };
{ $($any:tt)* } => { TypeCons::NoParse(stringify![$($any)*].to_string())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum Type {
Var(Var),
Cons(TypeCons),
Sum(TypeRec, TypeRec),
Prod(TypeRec, TypeRec),
Unit,
Ref(IdxTm, TypeRec),
Thk(IdxTm, CEffectRec),
IdxApp(TypeRec, IdxTm),
TypeApp(TypeRec, TypeRec),
Nm(IdxTm),
NmFn(NameTm),
TypeFn(Var, Kind, TypeRec),
IdxFn(Var, Sort, TypeRec),
Rec(Var, TypeRec),
Exists(Var, SortRec, Prop, TypeRec),
NoParse(String),
}
pub type TypeRec = Rc<Type>;
#[macro_export]
macro_rules! fgi_vtype {
{ fromast $ast:expr } => { $ast };
{ ($($type:tt)+) } => { fgi_vtype![$($type)+] };
{ D } => { Type::Cons(TypeCons::D) };
{ Bool } => { Type::Cons(TypeCons::Bool) };
{ Nat } => { Type::Cons(TypeCons::Nat) };
{ String } => { Type::Cons(TypeCons::String) };
{ Seq } => { Type::Cons(TypeCons::Seq) };
{ user($s:ident) } => { Type::Cons(TypeCons::User(
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 } => { Type::Var(stringify![$a].to_string()) };
{ $($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())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum CType {
Lift(Type),
Arrow(Type,CEffectRec),
NoParse(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())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum CEffect {
Cons(CType,Effect),
ForallType(Var,Kind,CEffectRec),
ForallIdx(Var,Sort,Prop,CEffectRec),
NoParse(String),
}
pub type CEffectRec = Rc<CEffect>;
#[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())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum Val {
Var(Var),
Unit,
Pair(ValRec, ValRec),
Inj1(ValRec),
Inj2(ValRec),
Roll(ValRec),
Name(Name),
NameFn(NameTm),
Anno(ValRec,Type),
ThunkAnon(ExpRec),
Bool(bool),
Nat(usize),
Str(String),
NoParse(String),
}
pub type ValRec = Rc<Val>;
#[macro_export]
macro_rules! fgi_val {
{ fromast $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)+])) };
{ 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())};
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum PrimApp {
NatEq(Val,Val),
NatLt(Val,Val),
NatLte(Val,Val),
NatPlus(Val,Val),
NameBin(Val,Val),
RefThunk(Val),
}
#[derive(Clone,Debug,Eq,PartialEq,Hash)]
pub enum Exp {
AnnoE(ExpRec,CEffect),
AnnoC(ExpRec,CType),
Force(Val),
Thunk(Val,ExpRec),
Unroll(Val,Var,ExpRec),
Fix(Var,ExpRec),
Ret(Val),
DefType(Var,Type,ExpRec),
Let(Var,ExpRec,ExpRec),
Lam(Var, ExpRec),
App(ExpRec, Val),
Split(Val, Var, Var, ExpRec),
Case(Val, Var, ExpRec, Var, ExpRec),
IfThenElse(Val, ExpRec, ExpRec),
Ref(Val,Val),
Get(Val),
Scope(Val,ExpRec),
NameFnApp(Val,Val),
PrimApp(PrimApp),
Unimp,
DebugLabel(Option<Name>,Option<String>,ExpRec),
NoParse(String),
}
pub type ExpRec = Rc<Exp>;
#[macro_export]
macro_rules! fgi_exp {
{ fromast $ast:expr } => { $ast };
{ $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)+] };
{ scope $v:tt $($e:tt)+ } => { Exp::Scope(
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)+]),
)};
{ 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)+]))
};
{ {$($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)+} $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 $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 ($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! 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)*]
};
}