mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-08-15 14:50:42 +03:00
Make with clauses take a bind and an argument
This commit is contained in:
parent
1bb6183559
commit
7697acd137
@ -78,7 +78,9 @@ pub fn check_uses<'a>(
|
||||
if let Some(pat) = term.pattern() {
|
||||
check_global_binds(pat, globals)
|
||||
}
|
||||
//eprintln!("\nterm: {}", term);
|
||||
for (child, binds) in term.children_mut_with_binds() {
|
||||
//eprintln!("child: {}\nbinds: {:?}", child, binds.clone().collect::<Vec<_>>());
|
||||
for bind in binds.clone() {
|
||||
push_scope(bind.as_ref(), scope);
|
||||
}
|
||||
|
@ -59,14 +59,17 @@ impl fmt::Display for Term {
|
||||
Term::App { tag, fun, arg } => {
|
||||
write!(f, "{}({} {})", tag.display_padded(), fun.display_app(tag), arg)
|
||||
}
|
||||
Term::Mat { arg, bnd, with, arms } => {
|
||||
Term::Mat { arg, bnd, with_bnd, with_arg, arms } => {
|
||||
write!(f, "match ")?;
|
||||
if let Some(bnd) = bnd {
|
||||
write!(f, "{} = ", bnd)?;
|
||||
}
|
||||
write!(f, "{} ", arg)?;
|
||||
if !with.is_empty() {
|
||||
write!(f, "with {} ", DisplayJoin(|| with, ", "))?;
|
||||
if !with_bnd.is_empty() {
|
||||
write!(f, "with ")?;
|
||||
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
|
||||
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
|
||||
}
|
||||
}
|
||||
write!(f, "{{ ")?;
|
||||
for arm in arms {
|
||||
@ -78,14 +81,17 @@ impl fmt::Display for Term {
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
Term::Swt { arg, bnd, with, pred, arms } => {
|
||||
Term::Swt { arg, bnd, with_bnd, with_arg, pred, arms } => {
|
||||
write!(f, "switch ")?;
|
||||
if let Some(bnd) = bnd {
|
||||
write!(f, "{bnd} = ")?;
|
||||
}
|
||||
write!(f, "{arg} ")?;
|
||||
if !with.is_empty() {
|
||||
write!(f, "with {} ", DisplayJoin(|| with, ", "))?;
|
||||
if !with_bnd.is_empty() {
|
||||
write!(f, "with ")?;
|
||||
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
|
||||
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
|
||||
}
|
||||
}
|
||||
write!(f, "{{ ")?;
|
||||
for (i, arm) in arms.iter().enumerate() {
|
||||
@ -101,14 +107,17 @@ impl fmt::Display for Term {
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
Term::Fold { bnd, arg, with, arms } => {
|
||||
Term::Fold { bnd, arg, with_bnd, with_arg, arms } => {
|
||||
write!(f, "fold ")?;
|
||||
if let Some(bnd) = bnd {
|
||||
write!(f, "{} = ", bnd)?;
|
||||
}
|
||||
write!(f, "{} ", arg)?;
|
||||
if !with.is_empty() {
|
||||
write!(f, "with {} ", DisplayJoin(|| with, ", "))?;
|
||||
if !with_bnd.is_empty() {
|
||||
write!(f, "with ")?;
|
||||
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
|
||||
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
|
||||
}
|
||||
}
|
||||
write!(f, "{{ ")?;
|
||||
for arm in arms {
|
||||
@ -120,7 +129,7 @@ impl fmt::Display for Term {
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
Term::Bend { bind, init, cond, step, base } => {
|
||||
Term::Bend { bnd: bind, arg: init, cond, step, base } => {
|
||||
write!(f, "bend ")?;
|
||||
for (bind, init) in bind.iter().zip(init) {
|
||||
if let Some(bind) = bind {
|
||||
@ -339,14 +348,17 @@ impl Term {
|
||||
Term::Oper { opr, fst, snd } => {
|
||||
write!(f, "({} {} {})", opr, fst.display_pretty(tab), snd.display_pretty(tab))
|
||||
}
|
||||
Term::Mat { bnd, arg, with, arms } => {
|
||||
Term::Mat { bnd, arg, with_bnd, with_arg, arms } => {
|
||||
write!(f, "match ")?;
|
||||
if let Some(bnd) = bnd {
|
||||
write!(f, "{} = ", bnd)?;
|
||||
}
|
||||
write!(f, "{} ", arg.display_pretty(tab))?;
|
||||
if !with.is_empty() {
|
||||
write!(f, "with {} ", DisplayJoin(|| with, ", "))?;
|
||||
if !with_bnd.is_empty() {
|
||||
write!(f, "with ")?;
|
||||
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
|
||||
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
|
||||
}
|
||||
}
|
||||
write!(f, "{{ ")?;
|
||||
for arm in arms {
|
||||
@ -358,14 +370,17 @@ impl Term {
|
||||
}
|
||||
write!(f, "\n{:tab$}}}", "")
|
||||
}
|
||||
Term::Swt { bnd, arg, with, pred, arms } => {
|
||||
Term::Swt { bnd, arg, with_bnd, with_arg, pred, arms } => {
|
||||
write!(f, "switch ")?;
|
||||
if let Some(bnd) = bnd {
|
||||
write!(f, "{bnd} = ")?;
|
||||
}
|
||||
write!(f, "{} ", arg.display_pretty(tab))?;
|
||||
if !with.is_empty() {
|
||||
write!(f, "with {} ", DisplayJoin(|| with, ", "))?;
|
||||
if !with_bnd.is_empty() {
|
||||
write!(f, "with ")?;
|
||||
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
|
||||
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
|
||||
}
|
||||
}
|
||||
writeln!(f, "{{")?;
|
||||
for (i, arm) in arms.iter().enumerate() {
|
||||
@ -381,14 +396,17 @@ impl Term {
|
||||
}
|
||||
write!(f, "{:tab$}}}", "")
|
||||
}
|
||||
Term::Fold { bnd, arg, with, arms } => {
|
||||
Term::Fold { bnd, arg, with_bnd, with_arg, arms } => {
|
||||
write!(f, "fold ")?;
|
||||
if let Some(bnd) = bnd {
|
||||
write!(f, "{} = ", bnd)?;
|
||||
}
|
||||
write!(f, "{} ", arg.display_pretty(tab))?;
|
||||
if !with.is_empty() {
|
||||
write!(f, "with {} ", DisplayJoin(|| with, ", "))?;
|
||||
if !with_bnd.is_empty() {
|
||||
write!(f, "with ")?;
|
||||
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
|
||||
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
|
||||
}
|
||||
}
|
||||
write!(f, "{{ ")?;
|
||||
for arm in arms {
|
||||
@ -400,7 +418,7 @@ impl Term {
|
||||
}
|
||||
write!(f, "\n{:tab$}}}", "")
|
||||
}
|
||||
Term::Bend { bind, init, cond, step, base } => {
|
||||
Term::Bend { bnd: bind, arg: init, cond, step, base } => {
|
||||
write!(f, "bend ")?;
|
||||
for (bind, init) in bind.iter().zip(init) {
|
||||
if let Some(bind) = bind {
|
||||
|
217
src/fun/mod.rs
217
src/fun/mod.rs
@ -130,28 +130,31 @@ pub enum Term {
|
||||
},
|
||||
/// Pattern matching on an ADT.
|
||||
Mat {
|
||||
arg: Box<Term>,
|
||||
bnd: Option<Name>,
|
||||
with: Vec<Name>,
|
||||
arg: Box<Term>,
|
||||
with_bnd: Vec<Option<Name>>,
|
||||
with_arg: Vec<Term>,
|
||||
arms: Vec<MatchRule>,
|
||||
},
|
||||
/// Native pattern matching on numbers
|
||||
Swt {
|
||||
arg: Box<Term>,
|
||||
bnd: Option<Name>,
|
||||
with: Vec<Name>,
|
||||
arg: Box<Term>,
|
||||
with_bnd: Vec<Option<Name>>,
|
||||
with_arg: Vec<Term>,
|
||||
pred: Option<Name>,
|
||||
arms: Vec<Term>,
|
||||
},
|
||||
Fold {
|
||||
bnd: Option<Name>,
|
||||
arg: Box<Term>,
|
||||
with: Vec<Name>,
|
||||
with_bnd: Vec<Option<Name>>,
|
||||
with_arg: Vec<Term>,
|
||||
arms: Vec<MatchRule>,
|
||||
},
|
||||
Bend {
|
||||
bind: Vec<Option<Name>>,
|
||||
init: Vec<Term>,
|
||||
bnd: Vec<Option<Name>>,
|
||||
arg: Vec<Term>,
|
||||
cond: Box<Term>,
|
||||
step: Box<Term>,
|
||||
base: Box<Term>,
|
||||
@ -326,22 +329,31 @@ impl Clone for Term {
|
||||
Self::Str { val } => Self::Str { val: val.clone() },
|
||||
Self::List { els } => Self::List { els: els.clone() },
|
||||
Self::Oper { opr, fst, snd } => Self::Oper { opr: *opr, fst: fst.clone(), snd: snd.clone() },
|
||||
Self::Mat { arg, bnd, with, arms } => {
|
||||
Self::Mat { arg: arg.clone(), bnd: bnd.clone(), with: with.clone(), arms: arms.clone() }
|
||||
}
|
||||
Self::Swt { arg, bnd, with, pred, arms } => Self::Swt {
|
||||
Self::Mat { arg, bnd, with_bnd, with_arg, arms } => Self::Mat {
|
||||
arg: arg.clone(),
|
||||
bnd: bnd.clone(),
|
||||
with: with.clone(),
|
||||
with_bnd: with_bnd.clone(),
|
||||
with_arg: with_arg.clone(),
|
||||
arms: arms.clone(),
|
||||
},
|
||||
Self::Swt { arg, bnd, with_bnd, with_arg, pred, arms } => Self::Swt {
|
||||
arg: arg.clone(),
|
||||
bnd: bnd.clone(),
|
||||
with_bnd: with_bnd.clone(),
|
||||
with_arg: with_arg.clone(),
|
||||
pred: pred.clone(),
|
||||
arms: arms.clone(),
|
||||
},
|
||||
Self::Fold { bnd, arg, with, arms } => {
|
||||
Self::Fold { bnd: bnd.clone(), arg: arg.clone(), with: with.clone(), arms: arms.clone() }
|
||||
}
|
||||
Self::Bend { bind, init, cond, step, base } => Self::Bend {
|
||||
bind: bind.clone(),
|
||||
init: init.clone(),
|
||||
Self::Fold { bnd, arg, with_bnd, with_arg, arms } => Self::Fold {
|
||||
bnd: bnd.clone(),
|
||||
arg: arg.clone(),
|
||||
with_bnd: with_bnd.clone(),
|
||||
with_arg: with_arg.clone(),
|
||||
arms: arms.clone(),
|
||||
},
|
||||
Self::Bend { bnd: bind, arg: init, cond, step, base } => Self::Bend {
|
||||
bnd: bind.clone(),
|
||||
arg: init.clone(),
|
||||
cond: cond.clone(),
|
||||
step: step.clone(),
|
||||
base: base.clone(),
|
||||
@ -412,6 +424,8 @@ impl Term {
|
||||
}
|
||||
|
||||
/// Wraps a term in lambdas, so that the outermost lambda is the first given element.
|
||||
///
|
||||
/// The lambda equivalent of [`Term::call`].
|
||||
pub fn rfold_lams(term: Term, pats: impl DoubleEndedIterator<Item = Option<Name>>) -> Self {
|
||||
pats.into_iter().rfold(term, |bod, nam| Self::lam(Pattern::Var(nam), bod))
|
||||
}
|
||||
@ -488,17 +502,17 @@ impl Term {
|
||||
pub fn children(&self) -> impl DoubleEndedIterator<Item = &Term> + Clone {
|
||||
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend, Fold });
|
||||
match self {
|
||||
Term::Mat { arg, bnd: _, with: _, arms } => {
|
||||
ChildrenIter::Mat([arg.as_ref()].into_iter().chain(arms.iter().map(|r| &r.2)))
|
||||
Term::Mat { arg, bnd: _, with_bnd: _, with_arg, arms } => {
|
||||
ChildrenIter::Mat([arg.as_ref()].into_iter().chain(with_arg.iter()).chain(arms.iter().map(|r| &r.2)))
|
||||
}
|
||||
Term::Swt { arg, bnd: _, with: _, pred: _, arms } => {
|
||||
ChildrenIter::Swt([arg.as_ref()].into_iter().chain(arms))
|
||||
Term::Swt { arg, bnd: _, with_bnd: _, with_arg, pred: _, arms } => {
|
||||
ChildrenIter::Swt([arg.as_ref()].into_iter().chain(with_arg.iter()).chain(arms))
|
||||
}
|
||||
Term::Bend { bind: _, init, cond, step, base } => {
|
||||
Term::Bend { bnd: _, arg: init, cond, step, base } => {
|
||||
ChildrenIter::Bend(init.iter().chain([cond.as_ref(), step.as_ref(), base.as_ref()]))
|
||||
}
|
||||
Term::Fold { bnd: _, arg, with: _, arms } => {
|
||||
ChildrenIter::Fold([arg.as_ref()].into_iter().chain(arms.iter().map(|r| &r.2)))
|
||||
Term::Fold { bnd: _, arg, with_bnd: _, with_arg, arms } => {
|
||||
ChildrenIter::Fold([arg.as_ref()].into_iter().chain(with_arg.iter()).chain(arms.iter().map(|r| &r.2)))
|
||||
}
|
||||
Term::Fan { els, .. } | Term::List { els } => ChildrenIter::Vec(els),
|
||||
Term::Let { val: fst, nxt: snd, .. }
|
||||
@ -523,18 +537,18 @@ impl Term {
|
||||
pub fn children_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Term> {
|
||||
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend, Fold });
|
||||
match self {
|
||||
Term::Mat { arg, bnd: _, with: _, arms } => {
|
||||
ChildrenIter::Mat([arg.as_mut()].into_iter().chain(arms.iter_mut().map(|r| &mut r.2)))
|
||||
Term::Mat { arg, bnd: _, with_bnd: _, with_arg, arms } => ChildrenIter::Mat(
|
||||
[arg.as_mut()].into_iter().chain(with_arg.iter_mut()).chain(arms.iter_mut().map(|r| &mut r.2)),
|
||||
),
|
||||
Term::Swt { arg, bnd: _, with_bnd: _, with_arg, pred: _, arms } => {
|
||||
ChildrenIter::Swt([arg.as_mut()].into_iter().chain(with_arg.iter_mut()).chain(arms))
|
||||
}
|
||||
Term::Swt { arg, bnd: _, with: _, pred: _, arms } => {
|
||||
ChildrenIter::Swt([arg.as_mut()].into_iter().chain(arms))
|
||||
}
|
||||
Term::Bend { bind: _, init, cond, step, base } => {
|
||||
Term::Bend { bnd: _, arg: init, cond, step, base } => {
|
||||
ChildrenIter::Bend(init.iter_mut().chain([cond.as_mut(), step.as_mut(), base.as_mut()]))
|
||||
}
|
||||
Term::Fold { bnd: _, arg, with: _, arms } => {
|
||||
ChildrenIter::Fold([arg.as_mut()].into_iter().chain(arms.iter_mut().map(|r| &mut r.2)))
|
||||
}
|
||||
Term::Fold { bnd: _, arg, with_bnd: _, with_arg, arms } => ChildrenIter::Fold(
|
||||
[arg.as_mut()].into_iter().chain(with_arg.iter_mut()).chain(arms.iter_mut().map(|r| &mut r.2)),
|
||||
),
|
||||
Term::Fan { els, .. } | Term::List { els } => ChildrenIter::Vec(els),
|
||||
Term::Let { val: fst, nxt: snd, .. }
|
||||
| Term::Ask { val: fst, nxt: snd, .. }
|
||||
@ -567,35 +581,36 @@ impl Term {
|
||||
&self,
|
||||
) -> impl DoubleEndedIterator<Item = (&Term, impl DoubleEndedIterator<Item = &Option<Name>> + Clone)> + Clone
|
||||
{
|
||||
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend, Fold });
|
||||
multi_iterator!(BindsIter { Zero, One, Mat, Pat, Bend });
|
||||
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend });
|
||||
multi_iterator!(BindsIter { Zero, One, Mat, Pat, SwtNum, SwtSucc, Bend });
|
||||
match self {
|
||||
Term::Mat { arg, bnd: _, with: _, arms } => ChildrenIter::Mat(
|
||||
[(arg.as_ref(), BindsIter::Zero([]))]
|
||||
.into_iter()
|
||||
.chain(arms.iter().map(move |r| (&r.2, BindsIter::Mat(r.1.iter())))),
|
||||
),
|
||||
Term::Swt { arg, bnd: _, with: _, pred, arms } => {
|
||||
Term::Mat { arg, bnd, with_bnd, with_arg, arms }
|
||||
| Term::Fold { bnd, arg, with_bnd, with_arg, arms } => {
|
||||
let arg = [(arg.as_ref(), BindsIter::Zero([]))].into_iter();
|
||||
let with_arg = with_arg.iter().map(|a| (a, BindsIter::Zero([])));
|
||||
let arms = arms
|
||||
.iter()
|
||||
.map(move |r| (&r.2, BindsIter::Mat([bnd].into_iter().chain(r.1.iter()).chain(with_bnd.iter()))));
|
||||
ChildrenIter::Mat(arg.chain(with_arg).chain(arms))
|
||||
}
|
||||
Term::Swt { arg, bnd, with_bnd, with_arg, pred, arms } => {
|
||||
let (succ, nums) = arms.split_last().unwrap();
|
||||
ChildrenIter::Swt(
|
||||
[(arg.as_ref(), BindsIter::Zero([]))]
|
||||
.into_iter()
|
||||
.chain(nums.iter().map(move |x| (x, BindsIter::Zero([]))))
|
||||
.chain([(succ, BindsIter::One([pred]))]),
|
||||
.chain(with_arg.iter().map(|a| (a, BindsIter::Zero([]))))
|
||||
.chain(nums.iter().map(move |x| (x, BindsIter::SwtNum([bnd].into_iter().chain(with_bnd.iter())))))
|
||||
.chain([(succ, BindsIter::SwtSucc([bnd, pred].into_iter().chain(with_bnd.iter())))]),
|
||||
)
|
||||
}
|
||||
Term::Bend { bind, init, cond, step, base } => {
|
||||
Term::Bend { bnd: bind, arg: init, cond, step, base } => {
|
||||
ChildrenIter::Bend(init.iter().map(|x| (x, BindsIter::Zero([]))).chain([
|
||||
(cond.as_ref(), BindsIter::Bend(bind.iter())),
|
||||
(step.as_ref(), BindsIter::Bend(bind.iter())),
|
||||
(base.as_ref(), BindsIter::Bend(bind.iter())),
|
||||
]))
|
||||
}
|
||||
Term::Fold { bnd: _, arg, with: _, arms } => ChildrenIter::Fold(
|
||||
[(arg.as_ref(), BindsIter::Zero([]))]
|
||||
.into_iter()
|
||||
.chain(arms.iter().map(move |r| (&r.2, BindsIter::Mat(r.1.iter())))),
|
||||
),
|
||||
|
||||
Term::Fan { els, .. } | Term::List { els } => {
|
||||
ChildrenIter::Vec(els.iter().map(|el| (el, BindsIter::Zero([]))))
|
||||
}
|
||||
@ -627,35 +642,38 @@ impl Term {
|
||||
&mut self,
|
||||
) -> impl DoubleEndedIterator<Item = (&mut Term, impl DoubleEndedIterator<Item = &Option<Name>> + Clone)>
|
||||
{
|
||||
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend, Fold });
|
||||
multi_iterator!(BindsIter { Zero, One, Mat, Pat, Bend });
|
||||
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend });
|
||||
multi_iterator!(BindsIter { Zero, One, Mat, SwtNum, SwtSucc, Pat, Bend });
|
||||
match self {
|
||||
Term::Mat { arg, bnd: _, with: _, arms: rules } => ChildrenIter::Mat(
|
||||
[(arg.as_mut(), BindsIter::Zero([]))]
|
||||
.into_iter()
|
||||
.chain(rules.iter_mut().map(move |r| (&mut r.2, BindsIter::Mat(r.1.iter())))),
|
||||
),
|
||||
Term::Swt { arg, bnd: _, with: _, pred, arms: rules } => {
|
||||
let (succ, nums) = rules.split_last_mut().unwrap();
|
||||
Term::Mat { arg, bnd, with_bnd, with_arg, arms }
|
||||
| Term::Fold { bnd, arg, with_bnd, with_arg, arms } => {
|
||||
let arg = [(arg.as_mut(), BindsIter::Zero([]))].into_iter();
|
||||
let with_arg = with_arg.iter_mut().map(|a| (a, BindsIter::Zero([])));
|
||||
let arms = arms
|
||||
.iter_mut()
|
||||
.map(|r| (&mut r.2, BindsIter::Mat([&*bnd].into_iter().chain(r.1.iter()).chain(with_bnd.iter()))));
|
||||
ChildrenIter::Mat(arg.chain(with_arg).chain(arms))
|
||||
}
|
||||
Term::Swt { arg, bnd, with_bnd, with_arg, pred, arms } => {
|
||||
let (succ, nums) = arms.split_last_mut().unwrap();
|
||||
ChildrenIter::Swt(
|
||||
[(arg.as_mut(), BindsIter::Zero([]))]
|
||||
.into_iter()
|
||||
.chain(nums.iter_mut().map(move |x| (x, BindsIter::Zero([]))))
|
||||
.chain([(succ, BindsIter::One([&*pred]))]),
|
||||
.chain(with_arg.iter_mut().map(|a| (a, BindsIter::Zero([]))))
|
||||
.chain(
|
||||
nums.iter_mut().map(|x| (x, BindsIter::SwtNum([&*bnd].into_iter().chain(with_bnd.iter())))),
|
||||
)
|
||||
.chain([(succ, BindsIter::SwtSucc([&*bnd, &*pred].into_iter().chain(with_bnd.iter())))]),
|
||||
)
|
||||
}
|
||||
Term::Bend { bind, init, cond, step, base } => {
|
||||
ChildrenIter::Bend(init.iter_mut().map(|x| (x, BindsIter::Zero([]))).chain([
|
||||
(cond.as_mut(), BindsIter::Bend(bind.iter())),
|
||||
(step.as_mut(), BindsIter::Bend(bind.iter())),
|
||||
(base.as_mut(), BindsIter::Bend(bind.iter())),
|
||||
Term::Bend { bnd, arg, cond, step, base } => {
|
||||
ChildrenIter::Bend(arg.iter_mut().map(|x| (x, BindsIter::Zero([]))).chain([
|
||||
(cond.as_mut(), BindsIter::Bend(bnd.iter())),
|
||||
(step.as_mut(), BindsIter::Bend(bnd.iter())),
|
||||
(base.as_mut(), BindsIter::Bend(bnd.iter())),
|
||||
]))
|
||||
}
|
||||
Term::Fold { bnd: _, arg, with: _, arms } => ChildrenIter::Fold(
|
||||
[(arg.as_mut(), BindsIter::Zero([]))]
|
||||
.into_iter()
|
||||
.chain(arms.iter_mut().map(move |r| (&mut r.2, BindsIter::Mat(r.1.iter())))),
|
||||
),
|
||||
|
||||
Term::Fan { els, .. } | Term::List { els } => {
|
||||
ChildrenIter::Vec(els.iter_mut().map(|el| (el, BindsIter::Zero([]))))
|
||||
}
|
||||
@ -681,63 +699,6 @@ impl Term {
|
||||
Term::Open { .. } => unreachable!("Open should be removed in earlier pass"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Must only be called after fix_matches.
|
||||
pub fn children_mut_with_binds_mut(
|
||||
&mut self,
|
||||
) -> impl DoubleEndedIterator<Item = (&mut Term, impl DoubleEndedIterator<Item = &mut Option<Name>>)> {
|
||||
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Fold });
|
||||
multi_iterator!(BindsIter { Zero, One, Mat, Pat });
|
||||
match self {
|
||||
Term::Mat { arg, bnd: _, with: _, arms: rules } => ChildrenIter::Mat(
|
||||
[(arg.as_mut(), BindsIter::Zero([]))]
|
||||
.into_iter()
|
||||
.chain(rules.iter_mut().map(move |r| (&mut r.2, BindsIter::Mat(r.1.iter_mut())))),
|
||||
),
|
||||
Term::Swt { arg, bnd: _, with: _, pred, arms: rules } => {
|
||||
let (succ, nums) = rules.split_last_mut().unwrap();
|
||||
ChildrenIter::Swt(
|
||||
[(arg.as_mut(), BindsIter::Zero([]))]
|
||||
.into_iter()
|
||||
.chain(nums.iter_mut().map(move |x| (x, BindsIter::Zero([]))))
|
||||
.chain([(succ, BindsIter::One([pred]))]),
|
||||
)
|
||||
}
|
||||
Term::Bend { .. } => {
|
||||
unreachable!("Term::Bend can't implement children_mut_with_binds_mut")
|
||||
}
|
||||
Term::Fold { bnd: _, arg, with: _, arms } => ChildrenIter::Fold(
|
||||
[(arg.as_mut(), BindsIter::Zero([]))]
|
||||
.into_iter()
|
||||
.chain(arms.iter_mut().map(move |r| (&mut r.2, BindsIter::Mat(r.1.iter_mut())))),
|
||||
),
|
||||
Term::Fan { els, .. } | Term::List { els } => {
|
||||
ChildrenIter::Vec(els.iter_mut().map(|el| (el, BindsIter::Zero([]))))
|
||||
}
|
||||
Term::Use { nam, val, nxt } => {
|
||||
ChildrenIter::Two([(val.as_mut(), BindsIter::Zero([])), (nxt.as_mut(), BindsIter::One([nam]))])
|
||||
}
|
||||
Term::Let { pat, val, nxt, .. } | Term::Ask { pat, val, nxt, .. } => ChildrenIter::Two([
|
||||
(val.as_mut(), BindsIter::Zero([])),
|
||||
(nxt.as_mut(), BindsIter::Pat(pat.binds_mut())),
|
||||
]),
|
||||
Term::App { fun: fst, arg: snd, .. } | Term::Oper { fst, snd, .. } => {
|
||||
ChildrenIter::Two([(fst.as_mut(), BindsIter::Zero([])), (snd.as_mut(), BindsIter::Zero([]))])
|
||||
}
|
||||
Term::Lam { pat, bod, .. } => ChildrenIter::One([(bod.as_mut(), BindsIter::Pat(pat.binds_mut()))]),
|
||||
Term::With { bod, .. } => ChildrenIter::One([(bod.as_mut(), BindsIter::Zero([]))]),
|
||||
Term::Var { .. }
|
||||
| Term::Link { .. }
|
||||
| Term::Num { .. }
|
||||
| Term::Nat { .. }
|
||||
| Term::Str { .. }
|
||||
| Term::Ref { .. }
|
||||
| Term::Era
|
||||
| Term::Err => ChildrenIter::Zero([]),
|
||||
Term::Open { .. } => unreachable!("Open should be removed in earlier pass"),
|
||||
}
|
||||
}
|
||||
|
||||
/* Common checks and transformations */
|
||||
|
||||
/// Substitute the occurrences of a variable in a term with the given term.
|
||||
|
@ -161,7 +161,14 @@ impl Reader<'_> {
|
||||
(zero_term, succ_term)
|
||||
}
|
||||
};
|
||||
Term::Swt { arg: Box::new(arg), bnd: Some(bnd), with: vec![], pred: None, arms: vec![zero, succ] }
|
||||
Term::Swt {
|
||||
arg: Box::new(arg),
|
||||
bnd: Some(bnd),
|
||||
with_arg: vec![],
|
||||
with_bnd: vec![],
|
||||
pred: None,
|
||||
arms: vec![zero, succ],
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.error(ReadbackError::InvalidNumericMatch);
|
||||
@ -588,8 +595,11 @@ impl Term {
|
||||
pub fn collect_unscoped(&self, unscoped: &mut HashSet<Name>, scope: &mut Vec<Name>) {
|
||||
maybe_grow(|| match self {
|
||||
Term::Var { nam } if !scope.contains(nam) => _ = unscoped.insert(nam.clone()),
|
||||
Term::Swt { arg, bnd, with: _, pred: _, arms } => {
|
||||
Term::Swt { arg, bnd, with_bnd: _, with_arg, pred: _, arms } => {
|
||||
arg.collect_unscoped(unscoped, scope);
|
||||
for arg in with_arg {
|
||||
arg.collect_unscoped(unscoped, scope);
|
||||
}
|
||||
arms[0].collect_unscoped(unscoped, scope);
|
||||
if let Some(bnd) = bnd {
|
||||
scope.push(Name::new(format!("{bnd}-1")));
|
||||
|
@ -16,7 +16,7 @@ use TSPL::Parser;
|
||||
// <Pattern> ::= "(" <Name> <Pattern>* ")" | <NameEra> | <Number> | "(" <Pattern> ("," <Pattern>)+ ")"
|
||||
// <Term> ::=
|
||||
// <Number> | <NumOp> | <Tup> | <App> | <Group> | <Nat> | <Lam> | <UnscopedLam> | <Bend> | <Fold> |
|
||||
// <Use> | <Dup> | <LetTup> | <Let> | <Bind> | <Match> | <Switch> | <Era> | <UnscopedVar> | <Var>
|
||||
// <Use> | <Dup> | <LetTup> | <Let> | <Do> | <Match> | <Switch> | <Era> | <UnscopedVar> | <Var>
|
||||
// <Lam> ::= <Tag>? ("λ"|"@") <NameEra> <Term>
|
||||
// <UnscopedLam>::= <Tag>? ("λ"|"@") "$" <Name> <Term>
|
||||
// <NumOp> ::= "(" <Operator> <Term> <Term> ")"
|
||||
@ -25,7 +25,7 @@ use TSPL::Parser;
|
||||
// <Group> ::= "(" <Term> ")"
|
||||
// <Use> ::= "use" <Name> "=" <Term> ";"? <Term>
|
||||
// <Let> ::= "let" <NameEra> "=" <Term> ";"? <Term>
|
||||
// <Bind> ::= "with" <Name> "{" <Ask> "}"
|
||||
// <With> ::= "with" <Name> "{" <Ask> "}"
|
||||
// <Ask> ::= "ask" <Pattern> "=" <Term> ";" <Term> | <Term>
|
||||
// <LetTup> ::= "let" "(" <NameEra> ("," <NameEra>)+ ")" "=" <Term> ";"? <Term>
|
||||
// <Dup> ::= "let" <Tag>? "{" <NameEra> (","? <NameEra>)+ "}" "=" <Term> ";"? <Term>
|
||||
@ -471,7 +471,8 @@ impl<'a> TermParser<'a> {
|
||||
return Ok(Term::Swt {
|
||||
arg: Box::new(cnd),
|
||||
bnd: Some(Name::new("%cond")),
|
||||
with: Vec::new(),
|
||||
with_bnd: Vec::new(),
|
||||
with_arg: Vec::new(),
|
||||
pred: Some(Name::new("%cond-1")),
|
||||
arms: vec![els, thn],
|
||||
});
|
||||
@ -480,17 +481,18 @@ impl<'a> TermParser<'a> {
|
||||
// Match
|
||||
if self.try_parse_keyword("match") {
|
||||
unexpected_tag(self)?;
|
||||
let (bnd, arg, with) = self.parse_match_header()?;
|
||||
let arms = self.list_like(|p| p.parse_match_arm(), "{", "}", ";", false, 1)?;
|
||||
return Ok(Term::Mat { arg: Box::new(arg), bnd, with, arms });
|
||||
let (bnd, arg) = self.parse_match_arg()?;
|
||||
let (with_bnd, with_arg) = self.parse_with_clause()?;
|
||||
let arms = self.list_like(|p| p.parse_match_arm(), "", "}", ";", false, 1)?;
|
||||
return Ok(Term::Mat { arg: Box::new(arg), bnd, with_bnd, with_arg, arms });
|
||||
}
|
||||
|
||||
// Switch
|
||||
if self.try_parse_keyword("switch") {
|
||||
unexpected_tag(self)?;
|
||||
let (bnd, arg, with) = self.parse_match_header()?;
|
||||
let (bnd, arg) = self.parse_match_arg()?;
|
||||
let (with_bnd, with_arg) = self.parse_with_clause()?;
|
||||
|
||||
self.consume("{")?;
|
||||
self.try_consume("|");
|
||||
self.consume("0")?;
|
||||
self.consume(":")?;
|
||||
@ -520,7 +522,7 @@ impl<'a> TermParser<'a> {
|
||||
self.try_consume(";");
|
||||
}
|
||||
let pred = Some(Name::new(format!("{}-{}", bnd.as_ref().unwrap(), arms.len() - 1)));
|
||||
return Ok(Term::Swt { arg: Box::new(arg), bnd, with, pred, arms });
|
||||
return Ok(Term::Swt { arg: Box::new(arg), bnd, with_bnd, with_arg, pred, arms });
|
||||
}
|
||||
|
||||
// With (monadic block)
|
||||
@ -536,9 +538,10 @@ impl<'a> TermParser<'a> {
|
||||
// Fold
|
||||
if self.try_parse_keyword("fold") {
|
||||
unexpected_tag(self)?;
|
||||
let (bnd, arg, with) = self.parse_match_header()?;
|
||||
let arms = self.list_like(|p| p.parse_match_arm(), "{", "}", ";", false, 1)?;
|
||||
return Ok(Term::Fold { arg: Box::new(arg), bnd, with, arms });
|
||||
let (bnd, arg) = self.parse_match_arg()?;
|
||||
let (with_bnd, with_arg) = self.parse_with_clause()?;
|
||||
let arms = self.list_like(|p| p.parse_match_arm(), "", "}", ";", false, 1)?;
|
||||
return Ok(Term::Fold { arg: Box::new(arg), bnd, with_bnd, with_arg, arms });
|
||||
}
|
||||
|
||||
// Bend
|
||||
@ -569,8 +572,8 @@ impl<'a> TermParser<'a> {
|
||||
let base = self.parse_term()?;
|
||||
self.consume("}")?;
|
||||
return Ok(Term::Bend {
|
||||
bind,
|
||||
init,
|
||||
bnd: bind,
|
||||
arg: init,
|
||||
cond: Box::new(cond),
|
||||
step: Box::new(step),
|
||||
base: Box::new(base),
|
||||
@ -636,6 +639,7 @@ impl<'a> TermParser<'a> {
|
||||
}))
|
||||
}
|
||||
|
||||
// A named arg with optional name.
|
||||
fn parse_match_arg(&mut self) -> ParseResult<(Option<Name>, Term)> {
|
||||
let ini_idx = *self.index();
|
||||
let mut arg = self.parse_term()?;
|
||||
@ -653,24 +657,29 @@ impl<'a> TermParser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_match_header(&mut self) -> ParseResult<(Option<Name>, Term, Vec<Name>)> {
|
||||
let (bnd, arg) = self.parse_match_arg()?;
|
||||
/// A named arg with non-optional name.
|
||||
fn parse_named_arg(&mut self) -> ParseResult<(Option<Name>, Term)> {
|
||||
let nam = self.parse_bend_name()?;
|
||||
self.skip_trivia();
|
||||
let with = if self.try_parse_keyword("with") {
|
||||
self.skip_trivia();
|
||||
let mut with = vec![self.parse_bend_name()?];
|
||||
self.skip_trivia();
|
||||
while !self.starts_with("{") {
|
||||
self.try_consume(",");
|
||||
self.skip_trivia();
|
||||
with.push(self.parse_bend_name()?);
|
||||
self.skip_trivia();
|
||||
}
|
||||
with
|
||||
if self.starts_with("=") {
|
||||
self.advance_one();
|
||||
let arg = self.parse_term()?;
|
||||
Ok((Some(nam), arg))
|
||||
} else {
|
||||
vec![]
|
||||
let arg = Term::Var { nam: nam.clone() };
|
||||
Ok((Some(nam), arg))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_with_clause(&mut self) -> ParseResult<(Vec<Option<Name>>, Vec<Term>)> {
|
||||
self.skip_trivia();
|
||||
let res = if self.try_parse_keyword("with") {
|
||||
self.list_like(|p| p.parse_named_arg(), "", "{", ",", false, 1)?.into_iter().unzip()
|
||||
} else {
|
||||
self.consume_exactly("{")?;
|
||||
(vec![], vec![])
|
||||
};
|
||||
Ok((bnd, arg, with))
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn parse_match_arm(&mut self) -> ParseResult<MatchRule> {
|
||||
|
@ -137,10 +137,13 @@ impl<'t, 'l> EncodeTermState<'t, 'l> {
|
||||
self.link(up, node.2);
|
||||
}
|
||||
// core: & arg ~ ?<(zero succ) ret>
|
||||
Term::Swt { arg, bnd: _, with, pred: _, arms: rules } => {
|
||||
Term::Swt { arg, bnd, with_bnd, with_arg, pred, arms, } => {
|
||||
// At this point should be only num matches of 0 and succ.
|
||||
assert!(with.is_empty());
|
||||
assert!(rules.len() == 2);
|
||||
assert!(bnd.is_none());
|
||||
assert!(with_bnd.is_empty());
|
||||
assert!(with_arg.is_empty());
|
||||
assert!(pred.is_none());
|
||||
assert!(arms.len() == 2);
|
||||
|
||||
self.created_nodes += 2;
|
||||
let loaned = Tree::Swi { fst: Box::new(Tree::Con{fst: Box::new(Tree::Era), snd: Box::new(Tree::Era)}), snd: Box::new(Tree::Era)};
|
||||
@ -152,8 +155,8 @@ impl<'t, 'l> EncodeTermState<'t, 'l> {
|
||||
});
|
||||
|
||||
self.encode_term(arg, Place::Tree(node));
|
||||
self.encode_term(&rules[0], Place::Hole(zero));
|
||||
self.encode_term(&rules[1], Place::Hole(succ));
|
||||
self.encode_term(&arms[0], Place::Hole(zero));
|
||||
self.encode_term(&arms[1], Place::Hole(succ));
|
||||
self.link(up, Place::Hole(out));
|
||||
}
|
||||
Term::Let { pat, val, nxt } => {
|
||||
|
@ -48,7 +48,7 @@ impl Term {
|
||||
if self.has_unscoped_diff() {
|
||||
return Err("Can't have non self-contained unscoped variables in a 'bend'".into());
|
||||
}
|
||||
let Term::Bend { bind, init, cond, step, base } = self else { unreachable!() };
|
||||
let Term::Bend { bnd, arg, cond, step, base } = self else { unreachable!() };
|
||||
|
||||
let new_nam = Name::new(format!("{}{}{}", def_name, NEW_FN_SEP, fresh));
|
||||
*fresh += 1;
|
||||
@ -59,8 +59,8 @@ impl Term {
|
||||
free_vars.remove(&Name::new(RECURSIVE_KW));
|
||||
free_vars.extend(base.free_vars());
|
||||
free_vars.extend(cond.free_vars());
|
||||
for bind in bind.iter().flatten() {
|
||||
free_vars.remove(bind);
|
||||
for bnd in bnd.iter().flatten() {
|
||||
free_vars.remove(bnd);
|
||||
}
|
||||
let free_vars = free_vars.into_keys().collect::<Vec<_>>();
|
||||
|
||||
@ -78,11 +78,12 @@ impl Term {
|
||||
let body = Term::Swt {
|
||||
arg: Box::new(std::mem::take(cond)),
|
||||
bnd: Some(Name::new("_")),
|
||||
with: vec![],
|
||||
with_bnd: vec![],
|
||||
with_arg: vec![],
|
||||
pred: Some(Name::new("_-1")),
|
||||
arms: vec![std::mem::take(base.as_mut()), step],
|
||||
};
|
||||
let body = Term::rfold_lams(body, std::mem::take(bind).into_iter());
|
||||
let body = Term::rfold_lams(body, std::mem::take(bnd).into_iter());
|
||||
let body = Term::rfold_lams(body, free_vars.iter().cloned().map(Some));
|
||||
|
||||
// Make a definition from the new function
|
||||
@ -93,7 +94,7 @@ impl Term {
|
||||
// Call the new function in the original term.
|
||||
let call =
|
||||
Term::call(Term::Ref { nam: new_nam }, free_vars.iter().map(|v| Term::Var { nam: v.clone() }));
|
||||
*self = Term::call(call, init.drain(..));
|
||||
*self = Term::call(call, arg.drain(..));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -67,7 +67,7 @@ impl Term {
|
||||
if self.has_unscoped_diff() {
|
||||
return Err("Can't have non self-contained unscoped variables in a 'fold'".into());
|
||||
}
|
||||
let Term::Fold { bnd: _, arg, with, arms } = self else { unreachable!() };
|
||||
let Term::Fold { bnd: _, arg, with_bnd, with_arg, arms } = self else { unreachable!() };
|
||||
|
||||
// Gather the free variables
|
||||
let mut free_vars = HashSet::new();
|
||||
@ -78,7 +78,7 @@ impl Term {
|
||||
}
|
||||
free_vars.extend(arm_free_vars);
|
||||
}
|
||||
for var in with.iter() {
|
||||
for var in with_bnd.iter().flatten() {
|
||||
free_vars.remove(var);
|
||||
}
|
||||
let free_vars = free_vars.into_iter().collect::<Vec<_>>();
|
||||
@ -103,19 +103,16 @@ impl Term {
|
||||
|
||||
// Create the new function
|
||||
let x_nam = Name::new("%x");
|
||||
let mut body = Term::Mat {
|
||||
let body = Term::Mat {
|
||||
arg: Box::new(Term::Var { nam: x_nam.clone() }),
|
||||
bnd: None,
|
||||
with: with.clone(),
|
||||
with_bnd: with_bnd.clone(),
|
||||
with_arg: with_bnd.iter().map(|nam| Term::var_or_era(nam.clone())).collect(),
|
||||
arms: std::mem::take(arms),
|
||||
};
|
||||
for nam in with.iter().rev() {
|
||||
body = Term::lam(Pattern::Var(Some(nam.clone())), body);
|
||||
}
|
||||
for nam in free_vars.iter().rev() {
|
||||
body = Term::lam(Pattern::Var(Some(nam.clone())), body);
|
||||
}
|
||||
body = Term::lam(Pattern::Var(Some(x_nam)), body);
|
||||
let body = Term::rfold_lams(body, with_bnd.iter().cloned());
|
||||
let body = Term::rfold_lams(body, free_vars.iter().map(|nam| Some(nam.clone())));
|
||||
let body = Term::lam(Pattern::Var(Some(x_nam)), body);
|
||||
let def =
|
||||
Definition { name: new_nam.clone(), rules: vec![Rule { pats: vec![], body }], builtin: false };
|
||||
new_defs.push(def);
|
||||
@ -123,7 +120,7 @@ impl Term {
|
||||
// Call the new function
|
||||
let call = Term::call(Term::Ref { nam: new_nam.clone() }, [std::mem::take(arg.as_mut())]);
|
||||
let call = Term::call(call, free_vars.iter().cloned().map(|nam| Term::Var { nam }));
|
||||
let call = Term::call(call, with.iter().cloned().map(|nam| Term::Var { nam }));
|
||||
let call = Term::call(call, with_arg.iter().cloned());
|
||||
*self = call;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -313,7 +313,9 @@ fn num_rule(
|
||||
let default_body = simplify_rule_match(args.clone(), new_rules, default_with, ctrs, adts)?;
|
||||
|
||||
// Linearize previously matched vars and current args.
|
||||
let swt_with = with.into_iter().chain(args).collect::<Vec<_>>();
|
||||
let with = with.into_iter().chain(args).collect::<Vec<_>>();
|
||||
let with_bnd = with.iter().cloned().map(Some).collect::<Vec<_>>();
|
||||
let with_arg = with.iter().cloned().map(|nam| Term::Var { nam }).collect::<Vec<_>>();
|
||||
|
||||
let term = num_bodies.into_iter().enumerate().rfold(default_body, |term, (i, body)| {
|
||||
let val = if i > 0 {
|
||||
@ -328,7 +330,8 @@ fn num_rule(
|
||||
Term::Swt {
|
||||
arg: Box::new(val),
|
||||
bnd: Some(arg.clone()),
|
||||
with: swt_with.clone(),
|
||||
with_bnd: with_bnd.clone(),
|
||||
with_arg: with_arg.clone(),
|
||||
pred: Some(pred_var.clone()),
|
||||
arms: vec![body, term],
|
||||
}
|
||||
@ -448,12 +451,15 @@ fn switch_rule(
|
||||
}
|
||||
|
||||
// Linearize previously matched vars and current args.
|
||||
let mat_with = with.into_iter().chain(old_args).collect::<Vec<_>>();
|
||||
let with = with.into_iter().chain(old_args).collect::<Vec<_>>();
|
||||
let with_bnd = with.iter().cloned().map(Some).collect::<Vec<_>>();
|
||||
let with_arg = with.iter().cloned().map(|nam| Term::Var { nam }).collect::<Vec<_>>();
|
||||
|
||||
let term = Term::Mat {
|
||||
arg: Box::new(Term::Var { nam: arg.clone() }),
|
||||
bnd: Some(arg.clone()),
|
||||
with: mat_with,
|
||||
with_bnd,
|
||||
with_arg,
|
||||
arms: new_arms,
|
||||
};
|
||||
Ok(term)
|
||||
|
@ -30,7 +30,8 @@ impl Term {
|
||||
*self = Term::Mat {
|
||||
arg: Box::new(Term::Var { nam: var.clone() }),
|
||||
bnd: Some(std::mem::take(var)),
|
||||
with: vec![],
|
||||
with_bnd: vec![],
|
||||
with_arg: vec![],
|
||||
arms: vec![(Some(ctr.clone()), vec![], std::mem::take(bod))],
|
||||
}
|
||||
} else {
|
||||
|
@ -52,7 +52,7 @@ fn encode_ctr_scott<'a>(
|
||||
let ctr = Term::Var { nam: ctr_name.clone() };
|
||||
let app = Term::call(ctr, ctr_args.clone().cloned().map(|nam| Term::Var { nam }));
|
||||
let lam = Term::rfold_lams(app, ctrs.into_iter().map(Some));
|
||||
ctr_args.cloned().rfold(lam, |acc, arg| Term::lam(Pattern::Var(Some(arg)), acc))
|
||||
Term::rfold_lams(lam, ctr_args.cloned().map(Some))
|
||||
}
|
||||
|
||||
fn encode_ctr_num_scott<'a>(ctr_args: impl DoubleEndedIterator<Item = &'a Name> + Clone, tag: &str) -> Term {
|
||||
|
@ -28,16 +28,18 @@ impl Term {
|
||||
child.encode_matches(adt_encoding)
|
||||
}
|
||||
|
||||
if let Term::Mat { arg, bnd: _, with, arms: rules } = self {
|
||||
assert!(with.is_empty());
|
||||
if let Term::Mat { arg, bnd: _, with_bnd, with_arg, arms } = self {
|
||||
assert!(with_bnd.is_empty());
|
||||
assert!(with_arg.is_empty());
|
||||
let arg = std::mem::take(arg.as_mut());
|
||||
let rules = std::mem::take(rules);
|
||||
let rules = std::mem::take(arms);
|
||||
*self = encode_match(arg, rules, adt_encoding);
|
||||
} else if let Term::Swt { arg, bnd: _, with, pred, arms: rules } = self {
|
||||
assert!(with.is_empty());
|
||||
} else if let Term::Swt { arg, bnd: _, with_bnd, with_arg, pred, arms } = self {
|
||||
assert!(with_bnd.is_empty());
|
||||
assert!(with_arg.is_empty());
|
||||
let arg = std::mem::take(arg.as_mut());
|
||||
let pred = std::mem::take(pred);
|
||||
let rules = std::mem::take(rules);
|
||||
let rules = std::mem::take(arms);
|
||||
*self = encode_switch(arg, pred, rules);
|
||||
}
|
||||
})
|
||||
@ -60,7 +62,8 @@ fn encode_match(arg: Term, rules: Vec<MatchRule>, adt_encoding: AdtEncoding) ->
|
||||
Term::Swt {
|
||||
arg: Box::new(Term::Var { nam: Name::new("%tag") }),
|
||||
bnd: None,
|
||||
with: vec![],
|
||||
with_bnd: vec![],
|
||||
with_arg: vec![],
|
||||
pred: None,
|
||||
arms: vec![std::mem::take(arm), make_switches(rest)],
|
||||
},
|
||||
@ -75,7 +78,8 @@ fn encode_match(arg: Term, rules: Vec<MatchRule>, adt_encoding: AdtEncoding) ->
|
||||
let term = Term::Swt {
|
||||
arg: Box::new(Term::Var { nam: Name::new("%tag") }),
|
||||
bnd: None,
|
||||
with: vec![],
|
||||
with_bnd: vec![],
|
||||
with_arg: vec![],
|
||||
pred: None,
|
||||
arms: vec![arm, Term::Era],
|
||||
};
|
||||
@ -100,12 +104,20 @@ fn encode_switch(arg: Term, pred: Option<Name>, mut rules: Vec<Term>) -> Term {
|
||||
nums.iter_mut().enumerate().rfold(last_arm, |term, (i, rule)| {
|
||||
let arms = vec![std::mem::take(rule), term];
|
||||
if i == 0 {
|
||||
Term::Swt { arg: Box::new(arg.clone()), bnd: None, with: vec![], pred: None, arms }
|
||||
Term::Swt {
|
||||
arg: Box::new(arg.clone()),
|
||||
bnd: None,
|
||||
with_bnd: vec![],
|
||||
with_arg: vec![],
|
||||
pred: None,
|
||||
arms,
|
||||
}
|
||||
} else {
|
||||
let swt = Term::Swt {
|
||||
arg: Box::new(Term::Var { nam: match_var.clone() }),
|
||||
bnd: None,
|
||||
with: vec![],
|
||||
with_bnd: vec![],
|
||||
with_arg: vec![],
|
||||
pred: None,
|
||||
arms,
|
||||
};
|
||||
|
@ -86,7 +86,8 @@ impl Term {
|
||||
}
|
||||
// Add a use term to each arm rebuilding the matched variable
|
||||
match self {
|
||||
Term::Mat { arg: _, bnd, with: _, arms } | Term::Fold { bnd, arg: _, with: _, arms } => {
|
||||
Term::Mat { arg: _, bnd, with_bnd: _, with_arg: _, arms }
|
||||
| Term::Fold { bnd, arg: _, with_bnd: _, with_arg: _, arms } => {
|
||||
for (ctr, fields, body) in arms {
|
||||
if let Some(ctr) = ctr {
|
||||
*body = Term::Use {
|
||||
@ -100,7 +101,7 @@ impl Term {
|
||||
}
|
||||
}
|
||||
}
|
||||
Term::Swt { arg: _, bnd, with: _, pred, arms } => {
|
||||
Term::Swt { arg: _, bnd, with_bnd: _, with_arg: _, pred, arms } => {
|
||||
let n_nums = arms.len() - 1;
|
||||
for (i, arm) in arms.iter_mut().enumerate() {
|
||||
let orig = if i == n_nums {
|
||||
@ -125,7 +126,9 @@ impl Term {
|
||||
}
|
||||
|
||||
fn fix_match(&mut self, errs: &mut Vec<FixMatchErr>, ctrs: &Constructors, adts: &Adts) {
|
||||
let (Term::Mat { arg: _, bnd, with: _, arms } | Term::Fold { bnd, arg: _, with: _, arms }) = self else {
|
||||
let (Term::Mat { arg: _, bnd, with_bnd: _, with_arg: _, arms }
|
||||
| Term::Fold { bnd, arg: _, with_bnd: _, with_arg: _, arms }) = self
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
let bnd = bnd.clone().unwrap();
|
||||
|
@ -236,11 +236,11 @@ impl Term {
|
||||
}
|
||||
}))
|
||||
}
|
||||
Term::Mat { arg, bnd: _, with: _, arms } => {
|
||||
FloatIter::Mat([arg.as_mut()].into_iter().chain(arms.iter_mut().map(|r| &mut r.2)))
|
||||
}
|
||||
Term::Swt { arg, bnd: _, with: _, pred: _, arms } => {
|
||||
FloatIter::Swt([arg.as_mut()].into_iter().chain(arms.iter_mut()))
|
||||
Term::Mat { arg, bnd: _, with_bnd: _, with_arg, arms } => FloatIter::Mat(
|
||||
[arg.as_mut()].into_iter().chain(with_arg.iter_mut()).chain(arms.iter_mut().map(|r| &mut r.2)),
|
||||
),
|
||||
Term::Swt { arg, bnd: _, with_bnd: _, with_arg, pred: _, arms } => {
|
||||
FloatIter::Swt([arg.as_mut()].into_iter().chain(with_arg.iter_mut()).chain(arms.iter_mut()))
|
||||
}
|
||||
Term::Fan { els, .. } | Term::List { els } => FloatIter::Vec(els),
|
||||
Term::Let { val: fst, nxt: snd, .. }
|
||||
|
@ -80,22 +80,32 @@ impl Term {
|
||||
})
|
||||
}
|
||||
|
||||
fn linearize_binds_single_match(&mut self, bind_terms: Vec<Term>) {
|
||||
let (used_vars, with, arms) = match self {
|
||||
Term::Mat { arg, bnd: _, with, arms } => {
|
||||
fn linearize_binds_single_match(&mut self, mut bind_terms: Vec<Term>) {
|
||||
let (used_vars, with_bnd, with_arg, arms) = match self {
|
||||
Term::Mat { arg, bnd: _, with_bnd, with_arg, arms } => {
|
||||
let vars = arg.free_vars().into_keys().collect::<HashSet<_>>();
|
||||
let arms = arms.iter_mut().map(|arm| &mut arm.2).collect::<Vec<_>>();
|
||||
(vars, with, arms)
|
||||
(vars, with_bnd, with_arg, arms)
|
||||
}
|
||||
Term::Swt { arg, bnd: _, with, pred: _, arms } => {
|
||||
Term::Swt { arg, bnd: _, with_bnd, with_arg, pred: _, arms } => {
|
||||
let vars = arg.free_vars().into_keys().collect::<HashSet<_>>();
|
||||
let arms = arms.iter_mut().collect();
|
||||
(vars, with, arms)
|
||||
(vars, with_bnd, with_arg, arms)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let (non_linearized, linearized) = fixed_and_linearized_terms(used_vars, bind_terms);
|
||||
// Add 'with' args as lets that can be moved
|
||||
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
|
||||
let term = Term::Let {
|
||||
pat: Box::new(Pattern::Var(bnd.clone())),
|
||||
val: Box::new(arg.clone()),
|
||||
nxt: Box::new(Term::Err),
|
||||
};
|
||||
bind_terms.push(term)
|
||||
}
|
||||
|
||||
let (mut non_linearized, linearized) = fixed_and_linearized_terms(used_vars, bind_terms);
|
||||
|
||||
// Add the linearized terms to the arms and recurse
|
||||
for arm in arms {
|
||||
@ -107,18 +117,31 @@ impl Term {
|
||||
let linearized_binds = linearized
|
||||
.iter()
|
||||
.flat_map(|t| match t {
|
||||
Term::Lam { pat, .. } | Term::Let { pat, .. } => pat.binds().flatten().collect::<Vec<_>>(),
|
||||
Term::Lam { pat, .. } | Term::Let { pat, .. } => pat.binds().flatten().cloned().collect::<Vec<_>>(),
|
||||
Term::Use { nam, .. } => {
|
||||
if let Some(nam) = nam {
|
||||
vec![nam]
|
||||
vec![nam.clone()]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect::<HashSet<_>>();
|
||||
with.retain(|w| !linearized_binds.contains(w));
|
||||
.collect::<BTreeSet<_>>();
|
||||
update_with_clause(with_bnd, with_arg, &linearized_binds);
|
||||
|
||||
// Remove the non-linearized 'with' binds from the terms that need
|
||||
// to be added back (since we didn't move them).
|
||||
non_linearized.retain(|term| {
|
||||
if let Term::Let { pat, .. } = term {
|
||||
if let Pattern::Var(bnd) = pat.as_ref() {
|
||||
if with_bnd.contains(bnd) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
// Add the non-linearized terms back to before the match
|
||||
self.wrap_with_bind_terms(non_linearized);
|
||||
@ -315,6 +338,24 @@ fn binds_fixed_by_dependency(used_in_arg: HashSet<Name>, bind_terms: &[Term]) ->
|
||||
fixed_binds
|
||||
}
|
||||
|
||||
fn update_with_clause(
|
||||
with_bnd: &mut Vec<Option<Name>>,
|
||||
with_arg: &mut Vec<Term>,
|
||||
vars_to_lift: &BTreeSet<Name>,
|
||||
) {
|
||||
let mut to_remove = Vec::new();
|
||||
for i in 0..with_bnd.len() {
|
||||
if let Some(with_bnd) = &with_bnd[i] {
|
||||
if vars_to_lift.contains(with_bnd) {
|
||||
to_remove.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (removed, to_remove) in to_remove.into_iter().enumerate() {
|
||||
with_bnd.remove(to_remove - removed);
|
||||
with_arg.remove(to_remove - removed);
|
||||
}
|
||||
}
|
||||
/* Linearize all used vars */
|
||||
|
||||
impl Book {
|
||||
@ -351,15 +392,17 @@ impl Term {
|
||||
/// Obs: This does not modify unscoped variables.
|
||||
pub fn lift_match_vars(match_term: &mut Term) -> &mut Term {
|
||||
// Collect match arms with binds
|
||||
let arms: Vec<_> = match match_term {
|
||||
Term::Mat { arg: _, bnd: _, with: _, arms: rules } => {
|
||||
rules.iter().map(|(_, binds, body)| (binds.iter().flatten().cloned().collect(), body)).collect()
|
||||
let (with_bnd, with_arg, arms) = match match_term {
|
||||
Term::Mat { arg: _, bnd: _, with_bnd, with_arg, arms: rules } => {
|
||||
let args =
|
||||
rules.iter().map(|(_, binds, body)| (binds.iter().flatten().cloned().collect(), body)).collect();
|
||||
(with_bnd.clone(), with_arg.clone(), args)
|
||||
}
|
||||
Term::Swt { arg: _, bnd: _, with: _, pred, arms } => {
|
||||
Term::Swt { arg: _, bnd: _, with_bnd, with_arg, pred, arms } => {
|
||||
let (succ, nums) = arms.split_last_mut().unwrap();
|
||||
let mut arms = nums.iter().map(|body| (vec![], body)).collect::<Vec<_>>();
|
||||
arms.push((vec![pred.clone().unwrap()], succ));
|
||||
arms
|
||||
(with_bnd.clone(), with_arg.clone(), arms)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
@ -380,27 +423,36 @@ pub fn lift_match_vars(match_term: &mut Term) -> &mut Term {
|
||||
|
||||
// Add lambdas to the arms
|
||||
match match_term {
|
||||
Term::Mat { arg: _, bnd: _, with, arms } => {
|
||||
with.retain(|with| !vars_to_lift.contains(with));
|
||||
Term::Mat { arg: _, bnd: _, with_bnd, with_arg, arms } => {
|
||||
update_with_clause(with_bnd, with_arg, &vars_to_lift);
|
||||
for arm in arms {
|
||||
let old_body = std::mem::take(&mut arm.2);
|
||||
arm.2 =
|
||||
vars_to_lift.iter().cloned().rfold(old_body, |body, nam| Term::lam(Pattern::Var(Some(nam)), body));
|
||||
arm.2 = Term::rfold_lams(old_body, vars_to_lift.iter().cloned().map(Some));
|
||||
}
|
||||
}
|
||||
Term::Swt { arg: _, bnd: _, with, pred: _, arms } => {
|
||||
with.retain(|with| !vars_to_lift.contains(with));
|
||||
Term::Swt { arg: _, bnd: _, with_bnd, with_arg, pred: _, arms } => {
|
||||
update_with_clause(with_bnd, with_arg, &vars_to_lift);
|
||||
for arm in arms {
|
||||
let old_body = std::mem::take(arm);
|
||||
*arm =
|
||||
vars_to_lift.iter().cloned().rfold(old_body, |body, nam| Term::lam(Pattern::Var(Some(nam)), body));
|
||||
*arm = Term::rfold_lams(old_body, vars_to_lift.iter().cloned().map(Some));
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
// Add apps to the match
|
||||
*match_term = vars_to_lift.into_iter().fold(std::mem::take(match_term), Term::arg_call);
|
||||
let args = vars_to_lift
|
||||
.into_iter()
|
||||
.map(|nam| {
|
||||
if let Some(idx) = with_bnd.iter().position(|x| x == &nam) {
|
||||
with_arg[idx].clone()
|
||||
} else {
|
||||
Term::Var { nam }
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let term = Term::call(std::mem::take(match_term), args);
|
||||
*match_term = term;
|
||||
|
||||
get_match_reference(match_term)
|
||||
}
|
||||
@ -439,38 +491,23 @@ impl Term {
|
||||
}
|
||||
});
|
||||
match self {
|
||||
Term::Mat { arg: _, bnd: _, with, arms: rules } => {
|
||||
// Linearize the vars in the `with` clause, but only the used ones.
|
||||
let with = retain_used_names(std::mem::take(with), rules.iter().map(|r| &r.2));
|
||||
for rule in rules {
|
||||
rule.2 = with
|
||||
.iter()
|
||||
.rfold(std::mem::take(&mut rule.2), |bod, nam| Term::lam(Pattern::Var(Some(nam.clone())), bod));
|
||||
Term::Mat { arg: _, bnd: _, with_bnd, with_arg, arms } => {
|
||||
for rule in arms {
|
||||
rule.2 = Term::rfold_lams(std::mem::take(&mut rule.2), with_bnd.clone().into_iter());
|
||||
}
|
||||
*self = Term::call(std::mem::take(self), with.into_iter().map(|nam| Term::Var { nam }));
|
||||
*with_bnd = vec![];
|
||||
let call_args = std::mem::take(with_arg).into_iter();
|
||||
*self = Term::call(std::mem::take(self), call_args);
|
||||
}
|
||||
Term::Swt { arg: _, bnd: _, with, pred: _, arms } => {
|
||||
let with = retain_used_names(std::mem::take(with), arms.iter());
|
||||
for arm in arms {
|
||||
*arm = with
|
||||
.iter()
|
||||
.rfold(std::mem::take(arm), |bod, nam| Term::lam(Pattern::Var(Some(nam.clone())), bod));
|
||||
Term::Swt { arg: _, bnd: _, with_bnd, with_arg, pred: _, arms } => {
|
||||
for rule in arms {
|
||||
*rule = Term::rfold_lams(std::mem::take(rule), with_bnd.clone().into_iter());
|
||||
}
|
||||
*self = Term::call(std::mem::take(self), with.into_iter().map(|nam| Term::Var { nam }));
|
||||
*with_bnd = vec![];
|
||||
let call_args = std::mem::take(with_arg).into_iter();
|
||||
*self = Term::call(std::mem::take(self), call_args);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// From a Vec of variable names, return the ones that are used inside `terms`.
|
||||
fn retain_used_names<'a>(mut names: Vec<Name>, terms: impl IntoIterator<Item = &'a Term>) -> Vec<Name> {
|
||||
let mut used_names = HashSet::new();
|
||||
for term in terms.into_iter() {
|
||||
let mut free_vars = term.free_vars();
|
||||
free_vars.retain(|_, uses| *uses > 0);
|
||||
used_names.extend(free_vars.into_keys());
|
||||
}
|
||||
names.retain(|nam| used_names.contains(nam));
|
||||
names
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
fun::{Book, FanKind, Name, Pattern, Tag, Term},
|
||||
maybe_grow,
|
||||
maybe_grow, multi_iterator,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -120,3 +120,54 @@ fn dup_name(nam: &Name, uses: u64) -> Name {
|
||||
Name::new(format!("{nam}_{uses}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Term {
|
||||
/// Because multiple children can share the same binds, this function is very restricted.
|
||||
/// Should only be called after desugaring bends/folds/matches/switches.
|
||||
pub fn children_mut_with_binds_mut(
|
||||
&mut self,
|
||||
) -> impl DoubleEndedIterator<Item = (&mut Term, impl DoubleEndedIterator<Item = &mut Option<Name>>)> {
|
||||
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Swt });
|
||||
multi_iterator!(BindsIter { Zero, One, Pat });
|
||||
match self {
|
||||
Term::Swt { arg, bnd, with_bnd, with_arg, pred, arms } => {
|
||||
debug_assert!(bnd.is_none());
|
||||
debug_assert!(with_bnd.is_empty());
|
||||
debug_assert!(with_arg.is_empty());
|
||||
debug_assert!(pred.is_none());
|
||||
ChildrenIter::Swt(
|
||||
[(arg.as_mut(), BindsIter::Zero([]))]
|
||||
.into_iter()
|
||||
.chain(arms.iter_mut().map(|x| (x, BindsIter::Zero([])))),
|
||||
)
|
||||
}
|
||||
Term::Fan { els, .. } | Term::List { els } => {
|
||||
ChildrenIter::Vec(els.iter_mut().map(|el| (el, BindsIter::Zero([]))))
|
||||
}
|
||||
Term::Use { nam, val, nxt } => {
|
||||
ChildrenIter::Two([(val.as_mut(), BindsIter::Zero([])), (nxt.as_mut(), BindsIter::One([nam]))])
|
||||
}
|
||||
Term::Let { pat, val, nxt, .. } | Term::Ask { pat, val, nxt, .. } => ChildrenIter::Two([
|
||||
(val.as_mut(), BindsIter::Zero([])),
|
||||
(nxt.as_mut(), BindsIter::Pat(pat.binds_mut())),
|
||||
]),
|
||||
Term::App { fun: fst, arg: snd, .. } | Term::Oper { fst, snd, .. } => {
|
||||
ChildrenIter::Two([(fst.as_mut(), BindsIter::Zero([])), (snd.as_mut(), BindsIter::Zero([]))])
|
||||
}
|
||||
Term::Lam { pat, bod, .. } => ChildrenIter::One([(bod.as_mut(), BindsIter::Pat(pat.binds_mut()))]),
|
||||
Term::Do { bod, .. } => ChildrenIter::One([(bod.as_mut(), BindsIter::Zero([]))]),
|
||||
Term::Var { .. }
|
||||
| Term::Link { .. }
|
||||
| Term::Num { .. }
|
||||
| Term::Nat { .. }
|
||||
| Term::Str { .. }
|
||||
| Term::Ref { .. }
|
||||
| Term::Era
|
||||
| Term::Err => ChildrenIter::Zero([]),
|
||||
Term::Mat { .. } => unreachable!("'match' should be removed in earlier pass"),
|
||||
Term::Fold { .. } => unreachable!("'fold' should be removed in earlier pass"),
|
||||
Term::Bend { .. } => unreachable!("'bend' should be removed in earlier pass"),
|
||||
Term::Open { .. } => unreachable!("'open' should be removed in earlier pass"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,26 +34,134 @@ pub struct UniqueNameGenerator {
|
||||
impl UniqueNameGenerator {
|
||||
// Recursively assign an id to each variable in the term, then convert each id into a unique name.
|
||||
pub fn unique_names_in_term(&mut self, term: &mut Term) {
|
||||
match term {
|
||||
// Note: we can't use the children iterators here because we mutate the binds,
|
||||
// which are shared across multiple children.
|
||||
maybe_grow(|| match term {
|
||||
Term::Var { nam } => *nam = self.use_var(nam),
|
||||
Term::Mat { with, .. } | Term::Swt { with, .. } => {
|
||||
for nam in with {
|
||||
*nam = self.use_var(nam);
|
||||
|
||||
Term::Mat { bnd, arg, with_bnd, with_arg, arms }
|
||||
| Term::Fold { bnd, arg, with_bnd, with_arg, arms } => {
|
||||
// Process args
|
||||
self.unique_names_in_term(arg);
|
||||
for arg in with_arg {
|
||||
self.unique_names_in_term(arg);
|
||||
}
|
||||
|
||||
// Add binds shared by all arms
|
||||
self.push(bnd.as_ref());
|
||||
for bnd in with_bnd.iter() {
|
||||
self.push(bnd.as_ref());
|
||||
}
|
||||
|
||||
// Process arms
|
||||
for arm in arms {
|
||||
// Add binds unique to each arm
|
||||
for bnd in arm.1.iter() {
|
||||
self.push(bnd.as_ref());
|
||||
}
|
||||
|
||||
// Process arm body
|
||||
self.unique_names_in_term(&mut arm.2);
|
||||
|
||||
// Remove binds unique to each arm
|
||||
for bnd in arm.1.iter_mut() {
|
||||
*bnd = self.pop(bnd.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
// Remove binds shared by all arms
|
||||
for bnd in with_bnd {
|
||||
*bnd = self.pop(bnd.as_ref());
|
||||
}
|
||||
*bnd = self.pop(bnd.as_ref());
|
||||
}
|
||||
|
||||
Term::Swt { bnd, arg, with_bnd, with_arg, pred, arms } => {
|
||||
self.unique_names_in_term(arg);
|
||||
for arg in with_arg {
|
||||
self.unique_names_in_term(arg);
|
||||
}
|
||||
|
||||
self.push(bnd.as_ref());
|
||||
for bnd in with_bnd.iter() {
|
||||
self.push(bnd.as_ref());
|
||||
}
|
||||
|
||||
let (succ, nums) = arms.split_last_mut().unwrap();
|
||||
for arm in nums.iter_mut() {
|
||||
self.unique_names_in_term(arm);
|
||||
}
|
||||
|
||||
self.push(pred.as_ref());
|
||||
self.unique_names_in_term(succ);
|
||||
*pred = self.pop(pred.as_ref());
|
||||
|
||||
for bnd in with_bnd {
|
||||
*bnd = self.pop(bnd.as_ref());
|
||||
}
|
||||
*bnd = self.pop(bnd.as_ref());
|
||||
}
|
||||
|
||||
Term::Bend { bnd, arg, cond, step, base } => {
|
||||
for arg in arg {
|
||||
self.unique_names_in_term(arg);
|
||||
}
|
||||
for bnd in bnd.iter() {
|
||||
self.push(bnd.as_ref());
|
||||
}
|
||||
self.unique_names_in_term(cond);
|
||||
self.unique_names_in_term(step);
|
||||
self.unique_names_in_term(base);
|
||||
for bnd in bnd {
|
||||
*bnd = self.pop(bnd.as_ref());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
maybe_grow(|| {
|
||||
for (child, binds) in term.children_mut_with_binds_mut() {
|
||||
let binds: Vec<_> = binds.collect();
|
||||
for bind in binds.iter() {
|
||||
self.push(bind.as_ref());
|
||||
|
||||
Term::Let { pat, val, nxt } | Term::Ask { pat, val, nxt } => {
|
||||
self.unique_names_in_term(val);
|
||||
for bnd in pat.binds() {
|
||||
self.push(bnd.as_ref());
|
||||
}
|
||||
self.unique_names_in_term(child);
|
||||
for bind in binds.into_iter().rev() {
|
||||
self.unique_names_in_term(nxt);
|
||||
for bind in pat.binds_mut() {
|
||||
*bind = self.pop(bind.as_ref());
|
||||
}
|
||||
}
|
||||
Term::Use { nam, val, nxt } => {
|
||||
self.unique_names_in_term(val);
|
||||
self.push(nam.as_ref());
|
||||
self.unique_names_in_term(nxt);
|
||||
*nam = self.pop(nam.as_ref());
|
||||
}
|
||||
Term::Lam { tag: _, pat, bod } => {
|
||||
for bind in pat.binds() {
|
||||
self.push(bind.as_ref());
|
||||
}
|
||||
self.unique_names_in_term(bod);
|
||||
for bind in pat.binds_mut() {
|
||||
*bind = self.pop(bind.as_ref());
|
||||
}
|
||||
}
|
||||
Term::Fan { fan: _, tag: _, els } | Term::List { els } => {
|
||||
for el in els {
|
||||
self.unique_names_in_term(el);
|
||||
}
|
||||
}
|
||||
Term::App { tag: _, fun: fst, arg: snd } | Term::Oper { opr: _, fst, snd } => {
|
||||
self.unique_names_in_term(fst);
|
||||
self.unique_names_in_term(snd);
|
||||
}
|
||||
Term::Do { typ: _, bod } => {
|
||||
self.unique_names_in_term(bod);
|
||||
}
|
||||
Term::Link { .. }
|
||||
| Term::Num { .. }
|
||||
| Term::Nat { .. }
|
||||
| Term::Str { .. }
|
||||
| Term::Ref { .. }
|
||||
| Term::Era
|
||||
| Term::Err => {}
|
||||
Term::Open { .. } => unreachable!("'open' should be removed in earlier pass"),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -57,31 +57,38 @@ impl Stmt {
|
||||
*self = gen_get(self, substitutions);
|
||||
}
|
||||
}
|
||||
Stmt::Match { bind: _, arg, arms, nxt } | Stmt::Fold { bind: _, arg, arms, with: _, nxt } => {
|
||||
Stmt::Match { bnd: _, arg, with_bnd: _, with_arg, arms, nxt }
|
||||
| Stmt::Fold { bnd: _, arg, arms, with_bnd: _, with_arg, nxt } => {
|
||||
for arm in arms.iter_mut() {
|
||||
arm.rgt.gen_map_get(id);
|
||||
}
|
||||
if let Some(nxt) = nxt {
|
||||
nxt.gen_map_get(id);
|
||||
}
|
||||
let substitutions = arg.substitute_map_gets(id);
|
||||
let mut substitutions = arg.substitute_map_gets(id);
|
||||
for arg in with_arg {
|
||||
substitutions.extend(arg.substitute_map_gets(id));
|
||||
}
|
||||
if !substitutions.is_empty() {
|
||||
*self = gen_get(self, substitutions);
|
||||
}
|
||||
}
|
||||
Stmt::Switch { bind: _, arg, arms, nxt } => {
|
||||
Stmt::Switch { bnd: _, arg, with_bnd: _, with_arg, arms, nxt } => {
|
||||
for arm in arms.iter_mut() {
|
||||
arm.gen_map_get(id);
|
||||
}
|
||||
if let Some(nxt) = nxt {
|
||||
nxt.gen_map_get(id);
|
||||
}
|
||||
let substitutions = arg.substitute_map_gets(id);
|
||||
let mut substitutions = arg.substitute_map_gets(id);
|
||||
for arg in with_arg {
|
||||
substitutions.extend(arg.substitute_map_gets(id));
|
||||
}
|
||||
if !substitutions.is_empty() {
|
||||
*self = gen_get(self, substitutions);
|
||||
}
|
||||
}
|
||||
Stmt::Bend { bind: _, init, cond, step, base, nxt } => {
|
||||
Stmt::Bend { bnd: _, arg: init, cond, step, base, nxt } => {
|
||||
step.gen_map_get(id);
|
||||
base.gen_map_get(id);
|
||||
if let Some(nxt) = nxt {
|
||||
@ -146,7 +153,7 @@ impl Expr {
|
||||
Expr::Lam { bod, .. } => {
|
||||
go(bod, substitutions, id);
|
||||
}
|
||||
Expr::Bin { lhs, rhs, .. } => {
|
||||
Expr::Opr { lhs, rhs, .. } => {
|
||||
go(lhs, substitutions, id);
|
||||
go(rhs, substitutions, id);
|
||||
}
|
||||
@ -155,24 +162,24 @@ impl Expr {
|
||||
go(el, substitutions, id);
|
||||
}
|
||||
}
|
||||
Expr::Constructor { kwargs, .. } => {
|
||||
Expr::Ctr { kwargs, .. } => {
|
||||
for (_, arg) in kwargs.iter_mut() {
|
||||
go(arg, substitutions, id);
|
||||
}
|
||||
}
|
||||
Expr::Comprehension { term, iter, cond, .. } => {
|
||||
Expr::LstMap { term, iter, cond, .. } => {
|
||||
go(term, substitutions, id);
|
||||
go(iter, substitutions, id);
|
||||
if let Some(cond) = cond {
|
||||
go(cond, substitutions, id);
|
||||
}
|
||||
}
|
||||
Expr::MapInit { entries } => {
|
||||
Expr::Map { entries } => {
|
||||
for (_, entry) in entries {
|
||||
go(entry, substitutions, id);
|
||||
}
|
||||
}
|
||||
Expr::Eraser | Expr::Str { .. } | Expr::Var { .. } | Expr::Chn { .. } | Expr::Num { .. } => {}
|
||||
Expr::Era | Expr::Str { .. } | Expr::Var { .. } | Expr::Chn { .. } | Expr::Num { .. } => {}
|
||||
}
|
||||
}
|
||||
let mut substitutions = Substitutions::new();
|
||||
|
@ -9,7 +9,7 @@ use interner::global::GlobalString;
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Expr {
|
||||
// "*"
|
||||
Eraser,
|
||||
Era,
|
||||
// [a-zA-Z_]+
|
||||
Var { nam: Name },
|
||||
// "$" [a-zA-Z_]+
|
||||
@ -21,7 +21,7 @@ pub enum Expr {
|
||||
// "lambda" {names}* ":" {bod}
|
||||
Lam { names: Vec<(Name, bool)>, bod: Box<Expr> },
|
||||
// {lhs} {op} {rhs}
|
||||
Bin { op: Op, lhs: Box<Expr>, rhs: Box<Expr> },
|
||||
Opr { op: Op, lhs: Box<Expr>, rhs: Box<Expr> },
|
||||
// "\"" ... "\""
|
||||
Str { val: GlobalString },
|
||||
// "[" ... "]"
|
||||
@ -31,11 +31,11 @@ pub enum Expr {
|
||||
// "{" {els} "}"
|
||||
Sup { els: Vec<Expr> },
|
||||
// {name} "{" {kwargs} "}"
|
||||
Constructor { name: Name, args: Vec<Expr>, kwargs: Vec<(Name, Expr)> },
|
||||
Ctr { name: Name, args: Vec<Expr>, kwargs: Vec<(Name, Expr)> },
|
||||
// "[" {term} "for" {bind} "in" {iter} ("if" {cond})? "]"
|
||||
Comprehension { term: Box<Expr>, bind: Name, iter: Box<Expr>, cond: Option<Box<Expr>> },
|
||||
LstMap { term: Box<Expr>, bind: Name, iter: Box<Expr>, cond: Option<Box<Expr>> },
|
||||
// "{" {entries} "}"
|
||||
MapInit { entries: Vec<(Expr, Expr)> },
|
||||
Map { entries: Vec<(Expr, Expr)> },
|
||||
// {map} "[" {key} "]"
|
||||
MapGet { nam: Name, key: Box<Expr> },
|
||||
}
|
||||
@ -106,7 +106,9 @@ pub enum Stmt {
|
||||
// <nxt>?
|
||||
Match {
|
||||
arg: Box<Expr>,
|
||||
bind: Option<Name>,
|
||||
bnd: Option<Name>,
|
||||
with_bnd: Vec<Option<Name>>,
|
||||
with_arg: Vec<Expr>,
|
||||
arms: Vec<MatchArm>,
|
||||
nxt: Option<Box<Stmt>>,
|
||||
},
|
||||
@ -116,7 +118,9 @@ pub enum Stmt {
|
||||
// <nxt>?
|
||||
Switch {
|
||||
arg: Box<Expr>,
|
||||
bind: Option<Name>,
|
||||
bnd: Option<Name>,
|
||||
with_bnd: Vec<Option<Name>>,
|
||||
with_arg: Vec<Expr>,
|
||||
arms: Vec<Stmt>,
|
||||
nxt: Option<Box<Stmt>>,
|
||||
},
|
||||
@ -126,8 +130,8 @@ pub enum Stmt {
|
||||
// {base}
|
||||
// <nxt>?
|
||||
Bend {
|
||||
bind: Vec<Option<Name>>,
|
||||
init: Vec<Expr>,
|
||||
bnd: Vec<Option<Name>>,
|
||||
arg: Vec<Expr>,
|
||||
cond: Box<Expr>,
|
||||
step: Box<Stmt>,
|
||||
base: Box<Stmt>,
|
||||
@ -139,8 +143,9 @@ pub enum Stmt {
|
||||
// <nxt>?
|
||||
Fold {
|
||||
arg: Box<Expr>,
|
||||
bind: Option<Name>,
|
||||
with: Vec<Name>,
|
||||
bnd: Option<Name>,
|
||||
with_bnd: Vec<Option<Name>>,
|
||||
with_arg: Vec<Expr>,
|
||||
arms: Vec<MatchArm>,
|
||||
nxt: Option<Box<Stmt>>,
|
||||
},
|
||||
|
@ -64,9 +64,9 @@ impl Stmt {
|
||||
nxt.order_kwargs(book)?;
|
||||
}
|
||||
}
|
||||
Stmt::Bend { bind: _, init, cond, step, base, nxt } => {
|
||||
for init in init {
|
||||
init.order_kwargs(book)?;
|
||||
Stmt::Bend { bnd: _, arg, cond, step, base, nxt } => {
|
||||
for arg in arg {
|
||||
arg.order_kwargs(book)?;
|
||||
}
|
||||
cond.order_kwargs(book)?;
|
||||
step.order_kwargs(book)?;
|
||||
@ -126,7 +126,7 @@ impl Expr {
|
||||
}
|
||||
}
|
||||
Expr::Lam { bod, .. } => bod.order_kwargs(book)?,
|
||||
Expr::Bin { lhs, rhs, .. } => {
|
||||
Expr::Opr { lhs, rhs, .. } => {
|
||||
lhs.order_kwargs(book)?;
|
||||
rhs.order_kwargs(book)?;
|
||||
}
|
||||
@ -135,14 +135,14 @@ impl Expr {
|
||||
el.order_kwargs(book)?;
|
||||
}
|
||||
}
|
||||
Expr::Comprehension { term, iter, cond, .. } => {
|
||||
Expr::LstMap { term, iter, cond, .. } => {
|
||||
term.order_kwargs(book)?;
|
||||
iter.order_kwargs(book)?;
|
||||
if let Some(cond) = cond {
|
||||
cond.order_kwargs(book)?;
|
||||
}
|
||||
}
|
||||
Expr::Constructor { name, args, kwargs } => match get_args_def_or_ctr(name, book) {
|
||||
Expr::Ctr { name, args, kwargs } => match get_args_def_or_ctr(name, book) {
|
||||
Some(names) => {
|
||||
go_order_kwargs(&names, args, kwargs)?;
|
||||
for arg in args {
|
||||
@ -151,13 +151,13 @@ impl Expr {
|
||||
}
|
||||
_ => return Err(format!("Constructor '{name}' not found.")),
|
||||
},
|
||||
Expr::MapInit { entries } => {
|
||||
Expr::Map { entries } => {
|
||||
for entry in entries {
|
||||
entry.1.order_kwargs(book)?;
|
||||
}
|
||||
}
|
||||
Expr::MapGet { .. }
|
||||
| Expr::Eraser
|
||||
| Expr::Era
|
||||
| Expr::Var { .. }
|
||||
| Expr::Chn { .. }
|
||||
| Expr::Num { .. }
|
||||
|
@ -112,7 +112,7 @@ impl<'a> PyParser<'a> {
|
||||
self.advance_one();
|
||||
// Empty map
|
||||
if self.try_consume("}") {
|
||||
return Ok(Expr::MapInit { entries: vec![] });
|
||||
return Ok(Expr::Map { entries: vec![] });
|
||||
}
|
||||
let head = self.parse_expr(false)?;
|
||||
self.skip_trivia();
|
||||
@ -148,7 +148,7 @@ impl<'a> PyParser<'a> {
|
||||
// Era
|
||||
'*' => {
|
||||
self.advance_one();
|
||||
Expr::Eraser
|
||||
Expr::Era
|
||||
}
|
||||
// Number
|
||||
c if is_num_char(c) => {
|
||||
@ -216,7 +216,7 @@ impl<'a> PyParser<'a> {
|
||||
if self.starts_with("{") {
|
||||
if let Expr::Var { nam } = base {
|
||||
let kwargs = self.list_like(|p| p.data_kwarg(), "{", "}", ",", true, 0)?;
|
||||
return Ok(Expr::Constructor { name: nam, args: Vec::new(), kwargs });
|
||||
return Ok(Expr::Ctr { name: nam, args: Vec::new(), kwargs });
|
||||
} else {
|
||||
return self.expected_spanned("Constructor name", ini_idx, end_idx);
|
||||
}
|
||||
@ -236,7 +236,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
let tail = self.list_like(|p| p.parse_map_entry(), "", "}", ",", true, 0)?;
|
||||
entries.extend(tail);
|
||||
Ok(Expr::MapInit { entries })
|
||||
Ok(Expr::Map { entries })
|
||||
}
|
||||
|
||||
fn parse_sup(&mut self, head: Expr) -> ParseResult<Expr> {
|
||||
@ -285,7 +285,7 @@ impl<'a> PyParser<'a> {
|
||||
cond = Some(Box::new(self.parse_expr(false)?));
|
||||
}
|
||||
self.consume("]")?;
|
||||
Ok(Expr::Comprehension { term: Box::new(head), bind, iter: Box::new(iter), cond })
|
||||
Ok(Expr::LstMap { term: Box::new(head), bind, iter: Box::new(iter), cond })
|
||||
} else {
|
||||
// List
|
||||
let mut head = vec![head];
|
||||
@ -368,7 +368,7 @@ impl<'a> PyParser<'a> {
|
||||
if op.precedence() == prec {
|
||||
self.parse_oper()?;
|
||||
let rhs = self.parse_infix_expr(prec + 1, inline)?;
|
||||
lhs = Expr::Bin { op, lhs: Box::new(lhs), rhs: Box::new(rhs) };
|
||||
lhs = Expr::Opr { op, lhs: Box::new(lhs), rhs: Box::new(rhs) };
|
||||
self.skip_trivia_inline();
|
||||
} else {
|
||||
break;
|
||||
@ -579,9 +579,9 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn parse_match(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> {
|
||||
let (bind, arg) = self.parse_match_arg()?;
|
||||
let (bnd, arg) = self.parse_match_arg()?;
|
||||
self.skip_trivia_inline();
|
||||
self.consume_exactly(":")?;
|
||||
let (with_bnd, with_arg) = self.parse_with_clause()?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
|
||||
@ -596,10 +596,10 @@ impl<'a> PyParser<'a> {
|
||||
indent.exit_level();
|
||||
if nxt_indent == *indent {
|
||||
let (nxt, nxt_indent) = self.parse_statement(indent)?;
|
||||
let stmt = Stmt::Match { arg: Box::new(arg), bind, arms, nxt: Some(Box::new(nxt)) };
|
||||
let stmt = Stmt::Match { arg: Box::new(arg), bnd, with_bnd, with_arg, arms, nxt: Some(Box::new(nxt)) };
|
||||
Ok((stmt, nxt_indent))
|
||||
} else {
|
||||
let stmt = Stmt::Match { arg: Box::new(arg), bind, arms, nxt: None };
|
||||
let stmt = Stmt::Match { arg: Box::new(arg), bnd, with_bnd, with_arg, arms, nxt: None };
|
||||
Ok((stmt, nxt_indent))
|
||||
}
|
||||
}
|
||||
@ -621,6 +621,28 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_with_clause(&mut self) -> ParseResult<(Vec<Option<Name>>, Vec<Expr>)> {
|
||||
self.skip_trivia_inline();
|
||||
let res = if self.try_parse_keyword("with") {
|
||||
self.list_like(|p| p.parse_with_arg(), "", ":", ",", true, 1)?.into_iter().unzip()
|
||||
} else {
|
||||
self.consume_exactly(":")?;
|
||||
(vec![], vec![])
|
||||
};
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn parse_with_arg(&mut self) -> ParseResult<(Option<Name>, Expr)> {
|
||||
let bind = self.parse_bend_name()?;
|
||||
self.skip_trivia_inline();
|
||||
if self.try_consume("=") {
|
||||
let arg = self.parse_expr(false)?;
|
||||
Ok((Some(bind), arg))
|
||||
} else {
|
||||
Ok((Some(bind.clone()), Expr::Var { nam: bind }))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_match_case(&mut self, indent: &mut Indent) -> ParseResult<(MatchArm, Indent)> {
|
||||
self.parse_keyword("case")?;
|
||||
self.skip_trivia_inline();
|
||||
@ -644,9 +666,9 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn parse_switch(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> {
|
||||
let (bind, arg) = self.parse_match_arg()?;
|
||||
let (bnd, arg) = self.parse_match_arg()?;
|
||||
self.skip_trivia_inline();
|
||||
self.consume_exactly(":")?;
|
||||
let (with_bnd, with_arg) = self.parse_with_clause()?;
|
||||
indent.enter_level();
|
||||
|
||||
self.consume_indent_exactly(*indent)?;
|
||||
@ -680,10 +702,10 @@ impl<'a> PyParser<'a> {
|
||||
indent.exit_level();
|
||||
if nxt_indent == *indent {
|
||||
let (nxt, nxt_indent) = self.parse_statement(indent)?;
|
||||
let stmt = Stmt::Switch { arg: Box::new(arg), bind, arms, nxt: Some(Box::new(nxt)) };
|
||||
let stmt = Stmt::Switch { arg: Box::new(arg), bnd, with_bnd, with_arg, arms, nxt: Some(Box::new(nxt)) };
|
||||
Ok((stmt, nxt_indent))
|
||||
} else {
|
||||
let stmt = Stmt::Switch { arg: Box::new(arg), bind, arms, nxt: None };
|
||||
let stmt = Stmt::Switch { arg: Box::new(arg), bnd, with_bnd, with_arg, arms, nxt: None };
|
||||
Ok((stmt, nxt_indent))
|
||||
}
|
||||
}
|
||||
@ -722,22 +744,7 @@ impl<'a> PyParser<'a> {
|
||||
// Actually identical to match, except the return
|
||||
let (bind, arg) = self.parse_match_arg()?;
|
||||
self.skip_trivia_inline();
|
||||
let with = if self.try_parse_keyword("with") {
|
||||
self.skip_trivia_inline();
|
||||
let mut with = vec![];
|
||||
while !self.starts_with(":") {
|
||||
with.push(self.parse_bend_name()?);
|
||||
self.skip_trivia_inline();
|
||||
if !self.starts_with(":") {
|
||||
self.consume_exactly(",")?;
|
||||
}
|
||||
self.skip_trivia_inline();
|
||||
}
|
||||
with
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
self.consume_exactly(":")?;
|
||||
let (with_bnd, with_arg) = self.parse_with_clause()?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
|
||||
@ -752,10 +759,11 @@ impl<'a> PyParser<'a> {
|
||||
indent.exit_level();
|
||||
if nxt_indent == *indent {
|
||||
let (nxt, nxt_indent) = self.parse_statement(indent)?;
|
||||
let stmt = Stmt::Fold { arg: Box::new(arg), bind, arms, with, nxt: Some(Box::new(nxt)) };
|
||||
let stmt =
|
||||
Stmt::Fold { arg: Box::new(arg), bnd: bind, arms, with_bnd, with_arg, nxt: Some(Box::new(nxt)) };
|
||||
Ok((stmt, nxt_indent))
|
||||
} else {
|
||||
let stmt = Stmt::Fold { arg: Box::new(arg), bind, arms, with, nxt: None };
|
||||
let stmt = Stmt::Fold { arg: Box::new(arg), bnd: bind, arms, with_bnd, with_arg, nxt: None };
|
||||
Ok((stmt, nxt_indent))
|
||||
}
|
||||
}
|
||||
@ -800,8 +808,8 @@ impl<'a> PyParser<'a> {
|
||||
if nxt_indent == *indent {
|
||||
let (nxt, nxt_indent) = self.parse_statement(indent)?;
|
||||
let stmt = Stmt::Bend {
|
||||
bind,
|
||||
init,
|
||||
bnd: bind,
|
||||
arg: init,
|
||||
cond: Box::new(cond),
|
||||
step: Box::new(step),
|
||||
base: Box::new(base),
|
||||
@ -810,8 +818,8 @@ impl<'a> PyParser<'a> {
|
||||
Ok((stmt, nxt_indent))
|
||||
} else {
|
||||
let stmt = Stmt::Bend {
|
||||
bind,
|
||||
init,
|
||||
bnd: bind,
|
||||
arg: init,
|
||||
cond: Box::new(cond),
|
||||
step: Box::new(step),
|
||||
base: Box::new(base),
|
||||
|
@ -135,13 +135,14 @@ impl Stmt {
|
||||
let term = fun::Term::Swt {
|
||||
arg: Box::new(cond.to_fun()),
|
||||
bnd: Some(Name::new("%pred")),
|
||||
with: Vec::new(),
|
||||
with_bnd: vec![],
|
||||
with_arg: vec![],
|
||||
pred: Some(Name::new("%pred-1")),
|
||||
arms,
|
||||
};
|
||||
wrap_nxt_assign_stmt(term, nxt, pat)?
|
||||
}
|
||||
Stmt::Match { arg, bind, arms, nxt } => {
|
||||
Stmt::Match { arg, bnd, with_bnd, with_arg, arms, nxt } => {
|
||||
let arg = arg.to_fun();
|
||||
let mut fun_arms = vec![];
|
||||
let mut arms = arms.into_iter();
|
||||
@ -150,6 +151,7 @@ impl Stmt {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let with_arg = with_arg.into_iter().map(Expr::to_fun).collect();
|
||||
fun_arms.push((fst.lft, vec![], fst_rgt));
|
||||
for arm in arms {
|
||||
let (arm_pat, arm_rgt) = match arm.rgt.into_fun()? {
|
||||
@ -170,10 +172,10 @@ impl Stmt {
|
||||
(None, None) => fun_arms.push((arm.lft, vec![], arm_rgt)),
|
||||
}
|
||||
}
|
||||
let term = fun::Term::Mat { arg: Box::new(arg), bnd: bind, with: Vec::new(), arms: fun_arms };
|
||||
let term = fun::Term::Mat { arg: Box::new(arg), bnd, with_bnd, with_arg, arms: fun_arms };
|
||||
wrap_nxt_assign_stmt(term, nxt, fst_pat)?
|
||||
}
|
||||
Stmt::Switch { arg, bind, arms, nxt } => {
|
||||
Stmt::Switch { arg, bnd, with_bnd, with_arg, arms, nxt } => {
|
||||
let arg = arg.to_fun();
|
||||
let mut fun_arms = vec![];
|
||||
let mut arms = arms.into_iter();
|
||||
@ -182,6 +184,7 @@ impl Stmt {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
let with_arg = with_arg.into_iter().map(Expr::to_fun).collect();
|
||||
fun_arms.push(fst);
|
||||
for arm in arms {
|
||||
let (arm_pat, arm) = match arm.into_fun()? {
|
||||
@ -202,11 +205,11 @@ impl Stmt {
|
||||
(None, None) => fun_arms.push(arm),
|
||||
}
|
||||
}
|
||||
let pred = Some(Name::new(format!("{}-{}", bind.clone().unwrap(), fun_arms.len() - 1)));
|
||||
let term = fun::Term::Swt { arg: Box::new(arg), bnd: bind, with: Vec::new(), pred, arms: fun_arms };
|
||||
let pred = Some(Name::new(format!("{}-{}", bnd.clone().unwrap(), fun_arms.len() - 1)));
|
||||
let term = fun::Term::Swt { arg: Box::new(arg), bnd, with_bnd, with_arg, pred, arms: fun_arms };
|
||||
wrap_nxt_assign_stmt(term, nxt, fst_pat)?
|
||||
}
|
||||
Stmt::Fold { arg, bind, arms, with, nxt } => {
|
||||
Stmt::Fold { arg, bnd, with_bnd, with_arg, arms, nxt } => {
|
||||
let arg = arg.to_fun();
|
||||
let mut fun_arms = vec![];
|
||||
let mut arms = arms.into_iter();
|
||||
@ -216,6 +219,7 @@ impl Stmt {
|
||||
StmtToFun::Assign(pat, term) => (Some(pat), term),
|
||||
};
|
||||
fun_arms.push((fst.lft, vec![], fst_rgt));
|
||||
let with_arg = with_arg.into_iter().map(Expr::to_fun).collect();
|
||||
for arm in arms {
|
||||
let (arm_pat, arm_rgt) = match arm.rgt.into_fun()? {
|
||||
StmtToFun::Return(term) => (None, term),
|
||||
@ -235,11 +239,11 @@ impl Stmt {
|
||||
(None, None) => fun_arms.push((arm.lft, vec![], arm_rgt)),
|
||||
}
|
||||
}
|
||||
let term = fun::Term::Fold { arg: Box::new(arg), bnd: bind, with, arms: fun_arms };
|
||||
let term = fun::Term::Fold { arg: Box::new(arg), bnd, with_bnd, with_arg, arms: fun_arms };
|
||||
wrap_nxt_assign_stmt(term, nxt, fst_pat)?
|
||||
}
|
||||
Stmt::Bend { bind, init, cond, step, base, nxt } => {
|
||||
let init = init.into_iter().map(Expr::to_fun).collect();
|
||||
Stmt::Bend { bnd, arg, cond, step, base, nxt } => {
|
||||
let arg = arg.into_iter().map(Expr::to_fun).collect();
|
||||
let cond = cond.to_fun();
|
||||
let (pat, step, base) = match (step.into_fun()?, base.into_fun()?) {
|
||||
(StmtToFun::Return(s), StmtToFun::Return(b)) => (None, s, b),
|
||||
@ -259,7 +263,7 @@ impl Stmt {
|
||||
}
|
||||
};
|
||||
let term =
|
||||
fun::Term::Bend { bind, init, cond: Box::new(cond), step: Box::new(step), base: Box::new(base) };
|
||||
fun::Term::Bend { bnd, arg, cond: Box::new(cond), step: Box::new(step), base: Box::new(base) };
|
||||
wrap_nxt_assign_stmt(term, nxt, pat)?
|
||||
}
|
||||
Stmt::With { typ, bod, nxt } => {
|
||||
@ -317,7 +321,7 @@ impl Stmt {
|
||||
impl Expr {
|
||||
pub fn to_fun(self) -> fun::Term {
|
||||
match self {
|
||||
Expr::Eraser => fun::Term::Era,
|
||||
Expr::Era => fun::Term::Era,
|
||||
Expr::Var { nam } => fun::Term::Var { nam },
|
||||
Expr::Chn { nam } => fun::Term::Link { nam },
|
||||
Expr::Num { val } => fun::Term::Num { val },
|
||||
@ -331,7 +335,7 @@ impl Expr {
|
||||
pat: Box::new(if link { fun::Pattern::Chn(name) } else { fun::Pattern::Var(Some(name)) }),
|
||||
bod: Box::new(acc),
|
||||
}),
|
||||
Expr::Bin { op, lhs, rhs } => {
|
||||
Expr::Opr { op, lhs, rhs } => {
|
||||
fun::Term::Oper { opr: op, fst: Box::new(lhs.to_fun()), snd: Box::new(rhs.to_fun()) }
|
||||
}
|
||||
Expr::Str { val } => fun::Term::Str { val },
|
||||
@ -346,12 +350,12 @@ impl Expr {
|
||||
tag: fun::Tag::Auto,
|
||||
els: els.into_iter().map(Self::to_fun).collect(),
|
||||
},
|
||||
Expr::Constructor { name, args, kwargs } => {
|
||||
Expr::Ctr { name, args, kwargs } => {
|
||||
assert!(kwargs.is_empty());
|
||||
let args = args.into_iter().map(Self::to_fun);
|
||||
fun::Term::call(fun::Term::Ref { nam: name }, args)
|
||||
}
|
||||
Expr::Comprehension { term, bind, iter, cond } => {
|
||||
Expr::LstMap { term, bind, iter, cond } => {
|
||||
const ITER_TAIL: &str = "%iter.tail";
|
||||
const ITER_HEAD: &str = "%iter.head";
|
||||
|
||||
@ -363,7 +367,8 @@ impl Expr {
|
||||
fun::Term::Swt {
|
||||
arg: Box::new(cond.to_fun()),
|
||||
bnd: Some(Name::new("%comprehension")),
|
||||
with: vec![],
|
||||
with_bnd: vec![],
|
||||
with_arg: vec![],
|
||||
pred: Some(Name::new("%comprehension-1")),
|
||||
arms: vec![fun::Term::Var { nam: Name::new(ITER_TAIL) }, cons_branch],
|
||||
}
|
||||
@ -379,14 +384,15 @@ impl Expr {
|
||||
fun::Term::Fold {
|
||||
bnd: Some(Name::new("%iter")),
|
||||
arg: Box::new(iter.to_fun()),
|
||||
with: Vec::new(),
|
||||
with_bnd: vec![],
|
||||
with_arg: vec![],
|
||||
arms: vec![
|
||||
(Some(Name::new(LNIL)), vec![], fun::Term::r#ref(LNIL)),
|
||||
(Some(Name::new(LCONS)), vec![], cons_branch),
|
||||
],
|
||||
}
|
||||
}
|
||||
Expr::MapInit { entries } => map_init(entries),
|
||||
Expr::Map { entries } => map_init(entries),
|
||||
Expr::MapGet { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -112,9 +112,8 @@ pub fn desugar_book(
|
||||
|
||||
ctx.check_unbound_vars()?;
|
||||
|
||||
ctx.book.make_var_names_unique();
|
||||
|
||||
// Auto match linearization
|
||||
ctx.book.make_var_names_unique();
|
||||
match opts.linearize_matches {
|
||||
OptLevel::Disabled => (),
|
||||
OptLevel::Alt => ctx.book.linearize_match_binds(),
|
||||
|
@ -228,10 +228,14 @@ fn simplify_matches() {
|
||||
ctx.set_entrypoint();
|
||||
ctx.book.encode_adts(AdtEncoding::NumScott);
|
||||
ctx.fix_match_defs()?;
|
||||
ctx.desugar_open()?;
|
||||
ctx.book.encode_builtins();
|
||||
ctx.resolve_refs()?;
|
||||
ctx.desugar_match_defs()?;
|
||||
ctx.fix_match_terms()?;
|
||||
ctx.desugar_bend()?;
|
||||
ctx.desugar_fold()?;
|
||||
ctx.desugar_do_blocks()?;
|
||||
ctx.check_unbound_vars()?;
|
||||
ctx.book.make_var_names_unique();
|
||||
ctx.book.linearize_match_binds();
|
||||
@ -273,10 +277,14 @@ fn encode_pattern_match() {
|
||||
ctx.set_entrypoint();
|
||||
ctx.book.encode_adts(adt_encoding);
|
||||
ctx.fix_match_defs()?;
|
||||
ctx.desugar_open()?;
|
||||
ctx.book.encode_builtins();
|
||||
ctx.resolve_refs()?;
|
||||
ctx.desugar_match_defs()?;
|
||||
ctx.fix_match_terms()?;
|
||||
ctx.desugar_bend()?;
|
||||
ctx.desugar_fold()?;
|
||||
ctx.desugar_do_blocks()?;
|
||||
ctx.check_unbound_vars()?;
|
||||
ctx.book.make_var_names_unique();
|
||||
ctx.book.linearize_match_binds();
|
||||
|
@ -1,5 +1,5 @@
|
||||
type Either = (Left value) | (Right value)
|
||||
type Bool = Bool/True | Bool/False
|
||||
type Bool = True | False
|
||||
|
||||
Foo (Either/Left Bool/False) (Either/Left Bool/False) = 1
|
||||
Foo (Either/Left Bool/False) (Either/Left Bool/True) = 1
|
||||
@ -20,3 +20,5 @@ Foo (Either/Right Bool/False) (Either/Left Bool/False) = 3
|
||||
Foo (Either/Right Bool/False) (Either/Left Bool/True) = 3
|
||||
Foo (Either/Right Bool/True) (Either/Left Bool/False) = 3
|
||||
Foo (Either/Right Bool/True) (Either/Left Bool/True) = 3
|
||||
|
||||
|
||||
|
14
tests/golden_tests/run_file/list_reverse_imp.bend
Normal file
14
tests/golden_tests/run_file/list_reverse_imp.bend
Normal file
@ -0,0 +1,14 @@
|
||||
def reverse(list):
|
||||
fold list with acc = []:
|
||||
case List/Nil:
|
||||
return acc
|
||||
case List/Cons:
|
||||
return list.tail(List/Cons(list.head, acc))
|
||||
|
||||
def main:
|
||||
bend n = 5:
|
||||
when n != 0:
|
||||
xs = List/Cons(n, fork(n - 1))
|
||||
else:
|
||||
xs = List/Nil
|
||||
return reverse(xs)
|
@ -5,13 +5,13 @@ input_file: tests/golden_tests/encode_pattern_match/bool.bend
|
||||
Scott
|
||||
(not) = λa (a bool/false bool/true)
|
||||
|
||||
(and) = λa (a λb (b bool/true bool/false) λc (c bool/false bool/false))
|
||||
(and) = λa (a λb (b bool/true bool/false) λd (d bool/false bool/false))
|
||||
|
||||
(and2) = λa (a λb b λ* bool/false)
|
||||
(and2) = λa (a λb b λd let * = d; bool/false)
|
||||
|
||||
(and3) = λa (a λb (b bool/true bool/false) λ* bool/false)
|
||||
(and3) = λa (a λb (b bool/true bool/false) λd let * = d; bool/false)
|
||||
|
||||
(and4) = λa (a λb (b bool/true bool/false) λ* bool/false)
|
||||
(and4) = λa (a λb (b bool/true bool/false) λd let * = d; bool/false)
|
||||
|
||||
(bool/true) = λa λ* a
|
||||
|
||||
@ -20,13 +20,13 @@ Scott
|
||||
NumScott
|
||||
(not) = λa (a λb switch b { 0: bool/false; _: λ* bool/true; })
|
||||
|
||||
(and) = λa (a λb switch b { 0: λc (c λd switch d { 0: bool/true; _: λ* bool/false; }); _: λ* λe (e λf switch f { 0: bool/false; _: λ* bool/false; }); })
|
||||
(and) = λa (a λb switch b { 0: λc (c λe switch e { 0: bool/true; _: λ* bool/false; }); _: λ* λf (f λh switch h { 0: bool/false; _: λ* bool/false; }); })
|
||||
|
||||
(and2) = λa (a λb switch b { 0: λc c; _: λ* λ* bool/false; })
|
||||
(and2) = λa (a λb switch b { 0: λc c; _: λ* λe let * = e; bool/false; })
|
||||
|
||||
(and3) = λa (a λb switch b { 0: λc (c λd switch d { 0: bool/true; _: λ* bool/false; }); _: λ* λ* bool/false; })
|
||||
(and3) = λa (a λb switch b { 0: λc (c λe switch e { 0: bool/true; _: λ* bool/false; }); _: λ* λf let * = f; bool/false; })
|
||||
|
||||
(and4) = λa (a λb switch b { 0: λc (c λd switch d { 0: bool/true; _: λ* bool/false; }); _: λ* λ* bool/false; })
|
||||
(and4) = λa (a λb switch b { 0: λc (c λe switch e { 0: bool/true; _: λ* bool/false; }); _: λ* λf let * = f; bool/false; })
|
||||
|
||||
(bool/true) = λa (a bool/true/tag)
|
||||
|
||||
|
@ -3,7 +3,7 @@ source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/encode_pattern_match/concat_def.bend
|
||||
---
|
||||
Scott
|
||||
(concat) = λa (a λb b λc λd λe (String/Cons c (concat d e)))
|
||||
(concat) = λa (a λb b λd λe λf (String/Cons d (concat e f)))
|
||||
|
||||
(main) = (concat (String/Cons 97 (String/Cons 98 String/Nil)) (String/Cons 99 (String/Cons 100 String/Nil)))
|
||||
|
||||
@ -12,7 +12,7 @@ Scott
|
||||
(String/Cons) = λa λb λ* λd (d a b)
|
||||
|
||||
NumScott
|
||||
(concat) = λa (a λb switch b { 0: λc c; _: λ* λd λe λf (String/Cons d (concat e f)); })
|
||||
(concat) = λa (a λb switch b { 0: λc c; _: λ* λe λf λg (String/Cons e (concat f g)); })
|
||||
|
||||
(main) = (concat (String/Cons 97 (String/Cons 98 String/Nil)) (String/Cons 99 (String/Cons 100 String/Nil)))
|
||||
|
||||
|
@ -3,31 +3,31 @@ source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/encode_pattern_match/definition_merge.bend
|
||||
---
|
||||
Scott
|
||||
(Foo) = λa (a λ* λc (c λ* 1 λ* 2) λ* λg (g λ* 3 λ* 3))
|
||||
(Foo) = λa (a λb (b λc (c λf (f 1 1) λg (g 2 2)) λh (h λk (k 1 1) λl (l 2 2))) λm (m λn (n λq (q 3 3) λr (r 3 3)) λs (s λv (v 3 3) λw (w 3 3))))
|
||||
|
||||
(Either/Left) = λa λb λ* (b a)
|
||||
|
||||
(Either/Right) = λa λ* λc (c a)
|
||||
|
||||
(Bool/Bool/True) = λa λ* a
|
||||
(Bool/True) = λa λ* a
|
||||
|
||||
(Bool/Bool/False) = λ* λb b
|
||||
(Bool/False) = λ* λb b
|
||||
|
||||
NumScott
|
||||
(Foo) = λa (a λb switch b { 0: λ* λd (d λe switch e { 0: λ* 1; _: λ* λ* 2; }); _: λ* λ* λi (i λj switch j { 0: λ* 3; _: λ* λ* 3; }); })
|
||||
(Foo) = λa (a λb switch b { 0: λc (c λd switch d { 0: λe (e λh switch h { 0: λi (i λj switch j { 0: 1; _: λ* 1; }); _: λ* λk (k λl switch l { 0: 2; _: λ* 2; }); }); _: λ* λm (m λp switch p { 0: λq (q λr switch r { 0: 1; _: λ* 1; }); _: λ* λs (s λt switch t { 0: 2; _: λ* 2; }); }); }); _: λ* λu (u λv switch v { 0: λw (w λz switch z { 0: λab (ab λbb switch bb { 0: 3; _: λ* 3; }); _: λ* λcb (cb λdb switch db { 0: 3; _: λ* 3; }); }); _: λ* λeb (eb λhb switch hb { 0: λib (ib λjb switch jb { 0: 3; _: λ* 3; }); _: λ* λkb (kb λlb switch lb { 0: 3; _: λ* 3; }); }); }); })
|
||||
|
||||
(Either/Left) = λa λb (b Either/Left/tag a)
|
||||
|
||||
(Either/Right) = λa λb (b Either/Right/tag a)
|
||||
|
||||
(Bool/Bool/True) = λa (a Bool/Bool/True/tag)
|
||||
(Bool/True) = λa (a Bool/True/tag)
|
||||
|
||||
(Bool/Bool/False) = λa (a Bool/Bool/False/tag)
|
||||
(Bool/False) = λa (a Bool/False/tag)
|
||||
|
||||
(Either/Left/tag) = 0
|
||||
|
||||
(Either/Right/tag) = 1
|
||||
|
||||
(Bool/Bool/True/tag) = 0
|
||||
(Bool/True/tag) = 0
|
||||
|
||||
(Bool/Bool/False/tag) = 1
|
||||
(Bool/False/tag) = 1
|
||||
|
@ -7,7 +7,7 @@ Scott
|
||||
|
||||
(Fn2) = λa let (*, c) = a; let (*, e) = c; let (f, *) = e; f
|
||||
|
||||
(Fn3) = λa let (b, *) = a; switch b { 0: λ* 0; _: λe λ* (+ e 1); }
|
||||
(Fn3) = λa let (b, c) = a; (switch b { 0: λ* λe let * = e; 0; _: λg λ* λi let * = i; (+ g 1); } c)
|
||||
|
||||
(main) = (Fn2 ((1, 2), (3, (4, (5, 6)))) 0)
|
||||
|
||||
@ -16,6 +16,6 @@ NumScott
|
||||
|
||||
(Fn2) = λa let (*, c) = a; let (*, e) = c; let (f, *) = e; f
|
||||
|
||||
(Fn3) = λa let (b, *) = a; switch b { 0: λ* 0; _: λe λ* (+ e 1); }
|
||||
(Fn3) = λa let (b, c) = a; (switch b { 0: λ* λe let * = e; 0; _: λg λ* λi let * = i; (+ g 1); } c)
|
||||
|
||||
(main) = (Fn2 ((1, 2), (3, (4, (5, 6)))) 0)
|
||||
|
@ -3,11 +3,11 @@ source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/encode_pattern_match/list_merge_sort.bend
|
||||
---
|
||||
Scott
|
||||
(If) = λa (a λb λ* b λ* λe e)
|
||||
(If) = λa (a λb λc let * = c; b λf λg let * = f; g)
|
||||
|
||||
(Pure) = λa (List_/Cons a List_/Nil)
|
||||
|
||||
(Map) = λa (a λb λc λd let {d d_2} = d; (List_/Cons (d b) (Map c d_2)) λ* List_/Nil)
|
||||
(Map) = λa (a λb λc λd let {e e_2} = d; (List_/Cons (e b) (Map c e_2)) λf let * = f; List_/Nil)
|
||||
|
||||
(MergeSort) = λa λb (Unpack a (Map b Pure))
|
||||
|
||||
@ -15,7 +15,7 @@ Scott
|
||||
|
||||
(MergePair) = λa λb (b λc λd λe (d λf λg λh let {h h_2} = h; λi (List_/Cons (Merge h i f) (MergePair h_2 g)) λ* λk (List_/Cons k List_/Nil) e c) λ* List_/Nil a)
|
||||
|
||||
(Merge) = λa λb (b λc λd λe λf (f λg let {g g_2 g_3} = g; λh let {h h_2} = h; λi let {i i_2 i_3} = i; λj let {j j_2 j_3} = j; λk let {k k_2} = k; (If (i j g) (List_/Cons j_2 (Merge i_2 k (List_/Cons g_2 h))) (List_/Cons g_3 (Merge i_3 (List_/Cons j_3 k_2) h_2))) λ* λo λp (List_/Cons o p) e c d) λ* λr r a)
|
||||
(Merge) = λa λb (b λc λd λe λf (f λh let {h h_2 h_3} = h; λi let {i i_2} = i; λj let {j j_2 j_3} = j; λk let {k k_2 k_3} = k; λl let {l l_2} = l; (If (j k h) (List_/Cons k_2 (Merge j_2 l (List_/Cons h_2 i))) (List_/Cons h_3 (Merge j_3 (List_/Cons k_3 l_2) i_2))) λ* λp λq (List_/Cons p q) e c d) λ* λs s a)
|
||||
|
||||
(Bool/True) = λa λ* a
|
||||
|
||||
@ -26,11 +26,11 @@ Scott
|
||||
(List_/Nil) = λ* λb b
|
||||
|
||||
NumScott
|
||||
(If) = λa (a λb switch b { 0: λc λ* c; _: λ* λ* λf f; })
|
||||
(If) = λa (a λb switch b { 0: λc λd let * = d; c; _: λ* λg λh let * = g; h; })
|
||||
|
||||
(Pure) = λa (List_/Cons a List_/Nil)
|
||||
|
||||
(Map) = λa (a λb switch b { 0: λc λd λe let {e e_2} = e; (List_/Cons (e c) (Map d e_2)); _: λ* λ* List_/Nil; })
|
||||
(Map) = λa (a λb switch b { 0: λc λd λe let {f f_2} = e; (List_/Cons (f c) (Map d f_2)); _: λ* λg let * = g; List_/Nil; })
|
||||
|
||||
(MergeSort) = λa λb (Unpack a (Map b Pure))
|
||||
|
||||
@ -38,7 +38,7 @@ NumScott
|
||||
|
||||
(MergePair) = λa λb (b λc switch c { 0: λd λe λf (e λg switch g { 0: λh λi λj let {j j_2} = j; λk (List_/Cons (Merge j k h) (MergePair j_2 i)); _: λ* λ* λm (List_/Cons m List_/Nil); } f d); _: λ* λ* List_/Nil; } a)
|
||||
|
||||
(Merge) = λa λb (b λc switch c { 0: λd λe λf λg (g λh switch h { 0: λi let {i i_2 i_3} = i; λj let {j j_2} = j; λk let {k k_2 k_3} = k; λl let {l l_2 l_3} = l; λm let {m m_2} = m; (If (k l i) (List_/Cons l_2 (Merge k_2 m (List_/Cons i_2 j))) (List_/Cons i_3 (Merge k_3 (List_/Cons l_3 m_2) j_2))); _: λ* λ* λq λr (List_/Cons q r); } f d e); _: λ* λ* λt t; } a)
|
||||
(Merge) = λa λb (b λc switch c { 0: λd λe λf λg (g λi switch i { 0: λj let {j j_2 j_3} = j; λk let {k k_2} = k; λl let {l l_2 l_3} = l; λm let {m m_2 m_3} = m; λn let {n n_2} = n; (If (l m j) (List_/Cons m_2 (Merge l_2 n (List_/Cons j_2 k))) (List_/Cons j_3 (Merge l_3 (List_/Cons m_3 n_2) k_2))); _: λ* λ* λr λs (List_/Cons r s); } f d e); _: λ* λ* λu u; } a)
|
||||
|
||||
(Bool/True) = λa (a Bool/True/tag)
|
||||
|
||||
|
9
tests/snapshots/run_file__list_reverse_imp.bend.snap
Normal file
9
tests/snapshots/run_file__list_reverse_imp.bend.snap
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/run_file/list_reverse_imp.bend
|
||||
---
|
||||
NumScott:
|
||||
[1, 2, 3, 4, 5]
|
||||
|
||||
Scott:
|
||||
[1, 2, 3, 4, 5]
|
@ -10,7 +10,7 @@ input_file: tests/golden_tests/simplify_matches/already_flat.bend
|
||||
|
||||
(Rule4) = λa match a { Foo/CtrA: λb b; Foo/CtrB c: c; }
|
||||
|
||||
(Rule5) = λa match a { Bar/CtrA1 b: λc (b c); Bar/CtrA2 d e: λf (d e f); Bar/CtrA3 g: λh (match h { Baz/CtrB0: λi (Bar/CtrA3 i); Baz/CtrB1 j: λk (Bar/CtrA3 k j); Baz/CtrB2 l: λm (Bar/CtrA3 m (Baz/CtrB2 l)); Baz/CtrB3 n: λo (o n); } g); }
|
||||
(Rule5) = λa match a { Bar/CtrA1 b: λc let d = c; (b d); Bar/CtrA2 e f: λg let h = g; (e f h); Bar/CtrA3 i: λj let k = j; (match k { Baz/CtrB0: λl (Bar/CtrA3 l); Baz/CtrB1 m: λn (Bar/CtrA3 n m); Baz/CtrB2 o: λp (Bar/CtrA3 p (Baz/CtrB2 o)); Baz/CtrB3 q: λr (r q); } i); }
|
||||
|
||||
(Rule6) = λa a
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/simplify_matches/double_unwrap_box.bend
|
||||
---
|
||||
(DoubleUnbox) = λa match a { Boxed/Box b: match b { Boxed/Box c: λd c; }; }
|
||||
(DoubleUnbox) = λa match a { Boxed/Box b: match b { Boxed/Box c: λd let e = d; let f = e; c; }; }
|
||||
|
||||
(Main) = (DoubleUnbox (Boxed/Box (Boxed/Box 0)) 5)
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/simplify_matches/double_unwrap_maybe.bend
|
||||
---
|
||||
(DoubleUnwrap) = λa match a { Maybe/Some b: match b { Maybe/Some c: λd c; Maybe/None: λe e; }; Maybe/None: λf f; }
|
||||
(DoubleUnwrap) = λa match a { Maybe/Some b: match b { Maybe/Some c: λd let e = d; let f = e; c; Maybe/None: λg let h = g; let i = h; i; }; Maybe/None: λj let k = j; k; }
|
||||
|
||||
(Main) = (DoubleUnwrap (Maybe/Some Maybe/None) 5)
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/simplify_matches/flatten_with_terminal.bend
|
||||
---
|
||||
(Foo) = λa switch a { 0: λb match b { A_t/A c: match c { B_t/B: B_t/B; }; }; _ d: λe *; }
|
||||
(Foo) = λa switch a { 0: λb let c = b; match c { A_t/A d: match d { B_t/B: B_t/B; }; }; _ e: λf let g = f; *; }
|
||||
|
||||
(main) = (Foo 2 (A_t/A B_t/B))
|
||||
|
||||
|
@ -10,7 +10,7 @@ input_file: tests/golden_tests/simplify_matches/linearize_match_all.bend
|
||||
|
||||
(D) = λa switch a { 0: λb λc c; _ d: λe λf (d f); }
|
||||
|
||||
(E) = λa match a { ConsList/Cons b c: λd (match d { ConsList/Cons e f: λg λh (g h e f); ConsList/Nil: λi λj (ConsList/Cons i j ConsList/Nil); } b c); ConsList/Nil: λk (ConsList/Nil k); }
|
||||
(E) = λa match a { ConsList/Cons b c: λd let e = d; (match e { ConsList/Cons f g: λh λi (h i f g); ConsList/Nil: λj λk (ConsList/Cons j k ConsList/Nil); } b c); ConsList/Nil: λl let m = l; (ConsList/Nil m); }
|
||||
|
||||
(A2) = λa match a { ConsList/Cons b c: λd λe (b c d e); ConsList/Nil: λf λg (f g); }
|
||||
|
||||
|
@ -2,6 +2,6 @@
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/simplify_matches/redundant_with_era.bend
|
||||
---
|
||||
(Fn2) = λa switch a { 0: λb let (c, d) = b; let (e, f) = d; f; _ g: λh let (i, j) = h; let (k, l) = j; l; }
|
||||
(Fn2) = λa switch a { 0: λb let c = b; let (d, e) = c; let (f, g) = e; g; _ h: λi let j = i; let (k, l) = j; let (m, n) = l; n; }
|
||||
|
||||
(main) = *
|
||||
|
Loading…
Reference in New Issue
Block a user