Make with clauses take a bind and an argument

This commit is contained in:
Nicolas Abril 2024-05-29 09:15:13 +02:00
parent 1bb6183559
commit 7697acd137
38 changed files with 687 additions and 410 deletions

View File

@ -78,7 +78,9 @@ pub fn check_uses<'a>(
if let Some(pat) = term.pattern() { if let Some(pat) = term.pattern() {
check_global_binds(pat, globals) check_global_binds(pat, globals)
} }
//eprintln!("\nterm: {}", term);
for (child, binds) in term.children_mut_with_binds() { for (child, binds) in term.children_mut_with_binds() {
//eprintln!("child: {}\nbinds: {:?}", child, binds.clone().collect::<Vec<_>>());
for bind in binds.clone() { for bind in binds.clone() {
push_scope(bind.as_ref(), scope); push_scope(bind.as_ref(), scope);
} }

View File

@ -59,14 +59,17 @@ impl fmt::Display for Term {
Term::App { tag, fun, arg } => { Term::App { tag, fun, arg } => {
write!(f, "{}({} {})", tag.display_padded(), fun.display_app(tag), 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 ")?; write!(f, "match ")?;
if let Some(bnd) = bnd { if let Some(bnd) = bnd {
write!(f, "{} = ", bnd)?; write!(f, "{} = ", bnd)?;
} }
write!(f, "{} ", arg)?; write!(f, "{} ", arg)?;
if !with.is_empty() { if !with_bnd.is_empty() {
write!(f, "with {} ", DisplayJoin(|| with, ", "))?; write!(f, "with ")?;
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
}
} }
write!(f, "{{ ")?; write!(f, "{{ ")?;
for arm in arms { for arm in arms {
@ -78,14 +81,17 @@ impl fmt::Display for Term {
} }
write!(f, "}}") write!(f, "}}")
} }
Term::Swt { arg, bnd, with, pred, arms } => { Term::Swt { arg, bnd, with_bnd, with_arg, pred, arms } => {
write!(f, "switch ")?; write!(f, "switch ")?;
if let Some(bnd) = bnd { if let Some(bnd) = bnd {
write!(f, "{bnd} = ")?; write!(f, "{bnd} = ")?;
} }
write!(f, "{arg} ")?; write!(f, "{arg} ")?;
if !with.is_empty() { if !with_bnd.is_empty() {
write!(f, "with {} ", DisplayJoin(|| with, ", "))?; write!(f, "with ")?;
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
}
} }
write!(f, "{{ ")?; write!(f, "{{ ")?;
for (i, arm) in arms.iter().enumerate() { for (i, arm) in arms.iter().enumerate() {
@ -101,14 +107,17 @@ impl fmt::Display for Term {
} }
write!(f, "}}") write!(f, "}}")
} }
Term::Fold { bnd, arg, with, arms } => { Term::Fold { bnd, arg, with_bnd, with_arg, arms } => {
write!(f, "fold ")?; write!(f, "fold ")?;
if let Some(bnd) = bnd { if let Some(bnd) = bnd {
write!(f, "{} = ", bnd)?; write!(f, "{} = ", bnd)?;
} }
write!(f, "{} ", arg)?; write!(f, "{} ", arg)?;
if !with.is_empty() { if !with_bnd.is_empty() {
write!(f, "with {} ", DisplayJoin(|| with, ", "))?; write!(f, "with ")?;
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
}
} }
write!(f, "{{ ")?; write!(f, "{{ ")?;
for arm in arms { for arm in arms {
@ -120,7 +129,7 @@ impl fmt::Display for Term {
} }
write!(f, "}}") write!(f, "}}")
} }
Term::Bend { bind, init, cond, step, base } => { Term::Bend { bnd: bind, arg: init, cond, step, base } => {
write!(f, "bend ")?; write!(f, "bend ")?;
for (bind, init) in bind.iter().zip(init) { for (bind, init) in bind.iter().zip(init) {
if let Some(bind) = bind { if let Some(bind) = bind {
@ -339,14 +348,17 @@ impl Term {
Term::Oper { opr, fst, snd } => { Term::Oper { opr, fst, snd } => {
write!(f, "({} {} {})", opr, fst.display_pretty(tab), snd.display_pretty(tab)) 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 ")?; write!(f, "match ")?;
if let Some(bnd) = bnd { if let Some(bnd) = bnd {
write!(f, "{} = ", bnd)?; write!(f, "{} = ", bnd)?;
} }
write!(f, "{} ", arg.display_pretty(tab))?; write!(f, "{} ", arg.display_pretty(tab))?;
if !with.is_empty() { if !with_bnd.is_empty() {
write!(f, "with {} ", DisplayJoin(|| with, ", "))?; write!(f, "with ")?;
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
}
} }
write!(f, "{{ ")?; write!(f, "{{ ")?;
for arm in arms { for arm in arms {
@ -358,14 +370,17 @@ impl Term {
} }
write!(f, "\n{:tab$}}}", "") write!(f, "\n{:tab$}}}", "")
} }
Term::Swt { bnd, arg, with, pred, arms } => { Term::Swt { bnd, arg, with_bnd, with_arg, pred, arms } => {
write!(f, "switch ")?; write!(f, "switch ")?;
if let Some(bnd) = bnd { if let Some(bnd) = bnd {
write!(f, "{bnd} = ")?; write!(f, "{bnd} = ")?;
} }
write!(f, "{} ", arg.display_pretty(tab))?; write!(f, "{} ", arg.display_pretty(tab))?;
if !with.is_empty() { if !with_bnd.is_empty() {
write!(f, "with {} ", DisplayJoin(|| with, ", "))?; write!(f, "with ")?;
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
}
} }
writeln!(f, "{{")?; writeln!(f, "{{")?;
for (i, arm) in arms.iter().enumerate() { for (i, arm) in arms.iter().enumerate() {
@ -381,14 +396,17 @@ impl Term {
} }
write!(f, "{:tab$}}}", "") write!(f, "{:tab$}}}", "")
} }
Term::Fold { bnd, arg, with, arms } => { Term::Fold { bnd, arg, with_bnd, with_arg, arms } => {
write!(f, "fold ")?; write!(f, "fold ")?;
if let Some(bnd) = bnd { if let Some(bnd) = bnd {
write!(f, "{} = ", bnd)?; write!(f, "{} = ", bnd)?;
} }
write!(f, "{} ", arg.display_pretty(tab))?; write!(f, "{} ", arg.display_pretty(tab))?;
if !with.is_empty() { if !with_bnd.is_empty() {
write!(f, "with {} ", DisplayJoin(|| with, ", "))?; write!(f, "with ")?;
for (bnd, arg) in with_bnd.iter().zip(with_arg.iter()) {
write!(f, "{} = {}, ", var_as_str(bnd), arg)?;
}
} }
write!(f, "{{ ")?; write!(f, "{{ ")?;
for arm in arms { for arm in arms {
@ -400,7 +418,7 @@ impl Term {
} }
write!(f, "\n{:tab$}}}", "") write!(f, "\n{:tab$}}}", "")
} }
Term::Bend { bind, init, cond, step, base } => { Term::Bend { bnd: bind, arg: init, cond, step, base } => {
write!(f, "bend ")?; write!(f, "bend ")?;
for (bind, init) in bind.iter().zip(init) { for (bind, init) in bind.iter().zip(init) {
if let Some(bind) = bind { if let Some(bind) = bind {

View File

@ -130,28 +130,31 @@ pub enum Term {
}, },
/// Pattern matching on an ADT. /// Pattern matching on an ADT.
Mat { Mat {
arg: Box<Term>,
bnd: Option<Name>, bnd: Option<Name>,
with: Vec<Name>, arg: Box<Term>,
with_bnd: Vec<Option<Name>>,
with_arg: Vec<Term>,
arms: Vec<MatchRule>, arms: Vec<MatchRule>,
}, },
/// Native pattern matching on numbers /// Native pattern matching on numbers
Swt { Swt {
arg: Box<Term>,
bnd: Option<Name>, bnd: Option<Name>,
with: Vec<Name>, arg: Box<Term>,
with_bnd: Vec<Option<Name>>,
with_arg: Vec<Term>,
pred: Option<Name>, pred: Option<Name>,
arms: Vec<Term>, arms: Vec<Term>,
}, },
Fold { Fold {
bnd: Option<Name>, bnd: Option<Name>,
arg: Box<Term>, arg: Box<Term>,
with: Vec<Name>, with_bnd: Vec<Option<Name>>,
with_arg: Vec<Term>,
arms: Vec<MatchRule>, arms: Vec<MatchRule>,
}, },
Bend { Bend {
bind: Vec<Option<Name>>, bnd: Vec<Option<Name>>,
init: Vec<Term>, arg: Vec<Term>,
cond: Box<Term>, cond: Box<Term>,
step: Box<Term>, step: Box<Term>,
base: Box<Term>, base: Box<Term>,
@ -326,22 +329,31 @@ impl Clone for Term {
Self::Str { val } => Self::Str { val: val.clone() }, Self::Str { val } => Self::Str { val: val.clone() },
Self::List { els } => Self::List { els: els.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::Oper { opr, fst, snd } => Self::Oper { opr: *opr, fst: fst.clone(), snd: snd.clone() },
Self::Mat { arg, bnd, with, arms } => { Self::Mat { arg, bnd, with_bnd, with_arg, arms } => Self::Mat {
Self::Mat { arg: arg.clone(), bnd: bnd.clone(), with: with.clone(), arms: arms.clone() }
}
Self::Swt { arg, bnd, with, pred, arms } => Self::Swt {
arg: arg.clone(), arg: arg.clone(),
bnd: bnd.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(), pred: pred.clone(),
arms: arms.clone(), arms: arms.clone(),
}, },
Self::Fold { bnd, arg, with, arms } => { Self::Fold { bnd, arg, with_bnd, with_arg, arms } => Self::Fold {
Self::Fold { bnd: bnd.clone(), arg: arg.clone(), with: with.clone(), arms: arms.clone() } bnd: bnd.clone(),
} arg: arg.clone(),
Self::Bend { bind, init, cond, step, base } => Self::Bend { with_bnd: with_bnd.clone(),
bind: bind.clone(), with_arg: with_arg.clone(),
init: init.clone(), arms: arms.clone(),
},
Self::Bend { bnd: bind, arg: init, cond, step, base } => Self::Bend {
bnd: bind.clone(),
arg: init.clone(),
cond: cond.clone(), cond: cond.clone(),
step: step.clone(), step: step.clone(),
base: base.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. /// 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 { 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)) 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 { pub fn children(&self) -> impl DoubleEndedIterator<Item = &Term> + Clone {
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend, Fold }); multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend, Fold });
match self { match self {
Term::Mat { arg, bnd: _, with: _, arms } => { Term::Mat { arg, bnd: _, with_bnd: _, with_arg, arms } => {
ChildrenIter::Mat([arg.as_ref()].into_iter().chain(arms.iter().map(|r| &r.2))) 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 } => { Term::Swt { arg, bnd: _, with_bnd: _, with_arg, pred: _, arms } => {
ChildrenIter::Swt([arg.as_ref()].into_iter().chain(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()])) ChildrenIter::Bend(init.iter().chain([cond.as_ref(), step.as_ref(), base.as_ref()]))
} }
Term::Fold { bnd: _, arg, with: _, arms } => { Term::Fold { bnd: _, arg, with_bnd: _, with_arg, arms } => {
ChildrenIter::Fold([arg.as_ref()].into_iter().chain(arms.iter().map(|r| &r.2))) 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::Fan { els, .. } | Term::List { els } => ChildrenIter::Vec(els),
Term::Let { val: fst, nxt: snd, .. } Term::Let { val: fst, nxt: snd, .. }
@ -523,18 +537,18 @@ impl Term {
pub fn children_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Term> { pub fn children_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Term> {
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend, Fold }); multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend, Fold });
match self { match self {
Term::Mat { arg, bnd: _, with: _, arms } => { Term::Mat { arg, bnd: _, with_bnd: _, with_arg, arms } => ChildrenIter::Mat(
ChildrenIter::Mat([arg.as_mut()].into_iter().chain(arms.iter_mut().map(|r| &mut r.2))) [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 } => { Term::Bend { bnd: _, arg: init, cond, step, base } => {
ChildrenIter::Swt([arg.as_mut()].into_iter().chain(arms))
}
Term::Bend { bind: _, init, cond, step, base } => {
ChildrenIter::Bend(init.iter_mut().chain([cond.as_mut(), step.as_mut(), base.as_mut()])) ChildrenIter::Bend(init.iter_mut().chain([cond.as_mut(), step.as_mut(), base.as_mut()]))
} }
Term::Fold { bnd: _, arg, with: _, arms } => { Term::Fold { bnd: _, arg, with_bnd: _, with_arg, arms } => ChildrenIter::Fold(
ChildrenIter::Fold([arg.as_mut()].into_iter().chain(arms.iter_mut().map(|r| &mut r.2))) [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::Fan { els, .. } | Term::List { els } => ChildrenIter::Vec(els),
Term::Let { val: fst, nxt: snd, .. } Term::Let { val: fst, nxt: snd, .. }
| Term::Ask { val: fst, nxt: snd, .. } | Term::Ask { val: fst, nxt: snd, .. }
@ -567,35 +581,36 @@ impl Term {
&self, &self,
) -> impl DoubleEndedIterator<Item = (&Term, impl DoubleEndedIterator<Item = &Option<Name>> + Clone)> + Clone ) -> impl DoubleEndedIterator<Item = (&Term, impl DoubleEndedIterator<Item = &Option<Name>> + Clone)> + Clone
{ {
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend, Fold }); multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend });
multi_iterator!(BindsIter { Zero, One, Mat, Pat, Bend }); multi_iterator!(BindsIter { Zero, One, Mat, Pat, SwtNum, SwtSucc, Bend });
match self { match self {
Term::Mat { arg, bnd: _, with: _, arms } => ChildrenIter::Mat( Term::Mat { arg, bnd, with_bnd, with_arg, arms }
[(arg.as_ref(), BindsIter::Zero([]))] | Term::Fold { bnd, arg, with_bnd, with_arg, arms } => {
.into_iter() let arg = [(arg.as_ref(), BindsIter::Zero([]))].into_iter();
.chain(arms.iter().map(move |r| (&r.2, BindsIter::Mat(r.1.iter())))), let with_arg = with_arg.iter().map(|a| (a, BindsIter::Zero([])));
), let arms = arms
Term::Swt { arg, bnd: _, with: _, pred, 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(); let (succ, nums) = arms.split_last().unwrap();
ChildrenIter::Swt( ChildrenIter::Swt(
[(arg.as_ref(), BindsIter::Zero([]))] [(arg.as_ref(), BindsIter::Zero([]))]
.into_iter() .into_iter()
.chain(nums.iter().map(move |x| (x, BindsIter::Zero([])))) .chain(with_arg.iter().map(|a| (a, BindsIter::Zero([]))))
.chain([(succ, BindsIter::One([pred]))]), .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([ ChildrenIter::Bend(init.iter().map(|x| (x, BindsIter::Zero([]))).chain([
(cond.as_ref(), BindsIter::Bend(bind.iter())), (cond.as_ref(), BindsIter::Bend(bind.iter())),
(step.as_ref(), BindsIter::Bend(bind.iter())), (step.as_ref(), BindsIter::Bend(bind.iter())),
(base.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 } => { Term::Fan { els, .. } | Term::List { els } => {
ChildrenIter::Vec(els.iter().map(|el| (el, BindsIter::Zero([])))) ChildrenIter::Vec(els.iter().map(|el| (el, BindsIter::Zero([]))))
} }
@ -627,35 +642,38 @@ impl Term {
&mut self, &mut self,
) -> impl DoubleEndedIterator<Item = (&mut Term, impl DoubleEndedIterator<Item = &Option<Name>> + Clone)> ) -> impl DoubleEndedIterator<Item = (&mut Term, impl DoubleEndedIterator<Item = &Option<Name>> + Clone)>
{ {
multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend, Fold }); multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat, Swt, Bend });
multi_iterator!(BindsIter { Zero, One, Mat, Pat, Bend }); multi_iterator!(BindsIter { Zero, One, Mat, SwtNum, SwtSucc, Pat, Bend });
match self { match self {
Term::Mat { arg, bnd: _, with: _, arms: rules } => ChildrenIter::Mat( Term::Mat { arg, bnd, with_bnd, with_arg, arms }
[(arg.as_mut(), BindsIter::Zero([]))] | Term::Fold { bnd, arg, with_bnd, with_arg, arms } => {
.into_iter() let arg = [(arg.as_mut(), BindsIter::Zero([]))].into_iter();
.chain(rules.iter_mut().map(move |r| (&mut r.2, BindsIter::Mat(r.1.iter())))), let with_arg = with_arg.iter_mut().map(|a| (a, BindsIter::Zero([])));
), let arms = arms
Term::Swt { arg, bnd: _, with: _, pred, arms: rules } => { .iter_mut()
let (succ, nums) = rules.split_last_mut().unwrap(); .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( ChildrenIter::Swt(
[(arg.as_mut(), BindsIter::Zero([]))] [(arg.as_mut(), BindsIter::Zero([]))]
.into_iter() .into_iter()
.chain(nums.iter_mut().map(move |x| (x, BindsIter::Zero([])))) .chain(with_arg.iter_mut().map(|a| (a, BindsIter::Zero([]))))
.chain([(succ, BindsIter::One([&*pred]))]), .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 } => { Term::Bend { bnd, arg, cond, step, base } => {
ChildrenIter::Bend(init.iter_mut().map(|x| (x, BindsIter::Zero([]))).chain([ ChildrenIter::Bend(arg.iter_mut().map(|x| (x, BindsIter::Zero([]))).chain([
(cond.as_mut(), BindsIter::Bend(bind.iter())), (cond.as_mut(), BindsIter::Bend(bnd.iter())),
(step.as_mut(), BindsIter::Bend(bind.iter())), (step.as_mut(), BindsIter::Bend(bnd.iter())),
(base.as_mut(), BindsIter::Bend(bind.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 } => { Term::Fan { els, .. } | Term::List { els } => {
ChildrenIter::Vec(els.iter_mut().map(|el| (el, BindsIter::Zero([])))) 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"), 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 */ /* Common checks and transformations */
/// Substitute the occurrences of a variable in a term with the given term. /// Substitute the occurrences of a variable in a term with the given term.

View File

@ -161,7 +161,14 @@ impl Reader<'_> {
(zero_term, succ_term) (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); self.error(ReadbackError::InvalidNumericMatch);
@ -588,8 +595,11 @@ impl Term {
pub fn collect_unscoped(&self, unscoped: &mut HashSet<Name>, scope: &mut Vec<Name>) { pub fn collect_unscoped(&self, unscoped: &mut HashSet<Name>, scope: &mut Vec<Name>) {
maybe_grow(|| match self { maybe_grow(|| match self {
Term::Var { nam } if !scope.contains(nam) => _ = unscoped.insert(nam.clone()), 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); arg.collect_unscoped(unscoped, scope);
for arg in with_arg {
arg.collect_unscoped(unscoped, scope);
}
arms[0].collect_unscoped(unscoped, scope); arms[0].collect_unscoped(unscoped, scope);
if let Some(bnd) = bnd { if let Some(bnd) = bnd {
scope.push(Name::new(format!("{bnd}-1"))); scope.push(Name::new(format!("{bnd}-1")));

View File

@ -16,7 +16,7 @@ use TSPL::Parser;
// <Pattern> ::= "(" <Name> <Pattern>* ")" | <NameEra> | <Number> | "(" <Pattern> ("," <Pattern>)+ ")" // <Pattern> ::= "(" <Name> <Pattern>* ")" | <NameEra> | <Number> | "(" <Pattern> ("," <Pattern>)+ ")"
// <Term> ::= // <Term> ::=
// <Number> | <NumOp> | <Tup> | <App> | <Group> | <Nat> | <Lam> | <UnscopedLam> | <Bend> | <Fold> | // <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> // <Lam> ::= <Tag>? ("λ"|"@") <NameEra> <Term>
// <UnscopedLam>::= <Tag>? ("λ"|"@") "$" <Name> <Term> // <UnscopedLam>::= <Tag>? ("λ"|"@") "$" <Name> <Term>
// <NumOp> ::= "(" <Operator> <Term> <Term> ")" // <NumOp> ::= "(" <Operator> <Term> <Term> ")"
@ -25,7 +25,7 @@ use TSPL::Parser;
// <Group> ::= "(" <Term> ")" // <Group> ::= "(" <Term> ")"
// <Use> ::= "use" <Name> "=" <Term> ";"? <Term> // <Use> ::= "use" <Name> "=" <Term> ";"? <Term>
// <Let> ::= "let" <NameEra> "=" <Term> ";"? <Term> // <Let> ::= "let" <NameEra> "=" <Term> ";"? <Term>
// <Bind> ::= "with" <Name> "{" <Ask> "}" // <With> ::= "with" <Name> "{" <Ask> "}"
// <Ask> ::= "ask" <Pattern> "=" <Term> ";" <Term> | <Term> // <Ask> ::= "ask" <Pattern> "=" <Term> ";" <Term> | <Term>
// <LetTup> ::= "let" "(" <NameEra> ("," <NameEra>)+ ")" "=" <Term> ";"? <Term> // <LetTup> ::= "let" "(" <NameEra> ("," <NameEra>)+ ")" "=" <Term> ";"? <Term>
// <Dup> ::= "let" <Tag>? "{" <NameEra> (","? <NameEra>)+ "}" "=" <Term> ";"? <Term> // <Dup> ::= "let" <Tag>? "{" <NameEra> (","? <NameEra>)+ "}" "=" <Term> ";"? <Term>
@ -471,7 +471,8 @@ impl<'a> TermParser<'a> {
return Ok(Term::Swt { return Ok(Term::Swt {
arg: Box::new(cnd), arg: Box::new(cnd),
bnd: Some(Name::new("%cond")), bnd: Some(Name::new("%cond")),
with: Vec::new(), with_bnd: Vec::new(),
with_arg: Vec::new(),
pred: Some(Name::new("%cond-1")), pred: Some(Name::new("%cond-1")),
arms: vec![els, thn], arms: vec![els, thn],
}); });
@ -480,17 +481,18 @@ impl<'a> TermParser<'a> {
// Match // Match
if self.try_parse_keyword("match") { if self.try_parse_keyword("match") {
unexpected_tag(self)?; unexpected_tag(self)?;
let (bnd, arg, with) = self.parse_match_header()?; let (bnd, arg) = self.parse_match_arg()?;
let arms = self.list_like(|p| p.parse_match_arm(), "{", "}", ";", false, 1)?; let (with_bnd, with_arg) = self.parse_with_clause()?;
return Ok(Term::Mat { arg: Box::new(arg), bnd, with, arms }); 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 // Switch
if self.try_parse_keyword("switch") { if self.try_parse_keyword("switch") {
unexpected_tag(self)?; 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.try_consume("|");
self.consume("0")?; self.consume("0")?;
self.consume(":")?; self.consume(":")?;
@ -520,7 +522,7 @@ impl<'a> TermParser<'a> {
self.try_consume(";"); self.try_consume(";");
} }
let pred = Some(Name::new(format!("{}-{}", bnd.as_ref().unwrap(), arms.len() - 1))); 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) // With (monadic block)
@ -536,9 +538,10 @@ impl<'a> TermParser<'a> {
// Fold // Fold
if self.try_parse_keyword("fold") { if self.try_parse_keyword("fold") {
unexpected_tag(self)?; unexpected_tag(self)?;
let (bnd, arg, with) = self.parse_match_header()?; let (bnd, arg) = self.parse_match_arg()?;
let arms = self.list_like(|p| p.parse_match_arm(), "{", "}", ";", false, 1)?; let (with_bnd, with_arg) = self.parse_with_clause()?;
return Ok(Term::Fold { arg: Box::new(arg), bnd, with, arms }); 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 // Bend
@ -569,8 +572,8 @@ impl<'a> TermParser<'a> {
let base = self.parse_term()?; let base = self.parse_term()?;
self.consume("}")?; self.consume("}")?;
return Ok(Term::Bend { return Ok(Term::Bend {
bind, bnd: bind,
init, arg: init,
cond: Box::new(cond), cond: Box::new(cond),
step: Box::new(step), step: Box::new(step),
base: Box::new(base), 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)> { fn parse_match_arg(&mut self) -> ParseResult<(Option<Name>, Term)> {
let ini_idx = *self.index(); let ini_idx = *self.index();
let mut arg = self.parse_term()?; 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>)> { /// A named arg with non-optional name.
let (bnd, arg) = self.parse_match_arg()?; fn parse_named_arg(&mut self) -> ParseResult<(Option<Name>, Term)> {
let nam = self.parse_bend_name()?;
self.skip_trivia(); self.skip_trivia();
let with = if self.try_parse_keyword("with") { if self.starts_with("=") {
self.skip_trivia(); self.advance_one();
let mut with = vec![self.parse_bend_name()?]; let arg = self.parse_term()?;
self.skip_trivia(); Ok((Some(nam), arg))
while !self.starts_with("{") {
self.try_consume(",");
self.skip_trivia();
with.push(self.parse_bend_name()?);
self.skip_trivia();
}
with
} else { } 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> { fn parse_match_arm(&mut self) -> ParseResult<MatchRule> {

View File

@ -137,10 +137,13 @@ impl<'t, 'l> EncodeTermState<'t, 'l> {
self.link(up, node.2); self.link(up, node.2);
} }
// core: & arg ~ ?<(zero succ) ret> // 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. // At this point should be only num matches of 0 and succ.
assert!(with.is_empty()); assert!(bnd.is_none());
assert!(rules.len() == 2); assert!(with_bnd.is_empty());
assert!(with_arg.is_empty());
assert!(pred.is_none());
assert!(arms.len() == 2);
self.created_nodes += 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)}; 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(arg, Place::Tree(node));
self.encode_term(&rules[0], Place::Hole(zero)); self.encode_term(&arms[0], Place::Hole(zero));
self.encode_term(&rules[1], Place::Hole(succ)); self.encode_term(&arms[1], Place::Hole(succ));
self.link(up, Place::Hole(out)); self.link(up, Place::Hole(out));
} }
Term::Let { pat, val, nxt } => { Term::Let { pat, val, nxt } => {

View File

@ -48,7 +48,7 @@ impl Term {
if self.has_unscoped_diff() { if self.has_unscoped_diff() {
return Err("Can't have non self-contained unscoped variables in a 'bend'".into()); 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)); let new_nam = Name::new(format!("{}{}{}", def_name, NEW_FN_SEP, fresh));
*fresh += 1; *fresh += 1;
@ -59,8 +59,8 @@ impl Term {
free_vars.remove(&Name::new(RECURSIVE_KW)); free_vars.remove(&Name::new(RECURSIVE_KW));
free_vars.extend(base.free_vars()); free_vars.extend(base.free_vars());
free_vars.extend(cond.free_vars()); free_vars.extend(cond.free_vars());
for bind in bind.iter().flatten() { for bnd in bnd.iter().flatten() {
free_vars.remove(bind); free_vars.remove(bnd);
} }
let free_vars = free_vars.into_keys().collect::<Vec<_>>(); let free_vars = free_vars.into_keys().collect::<Vec<_>>();
@ -78,11 +78,12 @@ impl Term {
let body = Term::Swt { let body = Term::Swt {
arg: Box::new(std::mem::take(cond)), arg: Box::new(std::mem::take(cond)),
bnd: Some(Name::new("_")), bnd: Some(Name::new("_")),
with: vec![], with_bnd: vec![],
with_arg: vec![],
pred: Some(Name::new("_-1")), pred: Some(Name::new("_-1")),
arms: vec![std::mem::take(base.as_mut()), step], 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)); let body = Term::rfold_lams(body, free_vars.iter().cloned().map(Some));
// Make a definition from the new function // Make a definition from the new function
@ -93,7 +94,7 @@ impl Term {
// Call the new function in the original term. // Call the new function in the original term.
let call = let call =
Term::call(Term::Ref { nam: new_nam }, free_vars.iter().map(|v| Term::Var { nam: v.clone() })); 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(()) Ok(())

View File

@ -67,7 +67,7 @@ impl Term {
if self.has_unscoped_diff() { if self.has_unscoped_diff() {
return Err("Can't have non self-contained unscoped variables in a 'fold'".into()); 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 // Gather the free variables
let mut free_vars = HashSet::new(); let mut free_vars = HashSet::new();
@ -78,7 +78,7 @@ impl Term {
} }
free_vars.extend(arm_free_vars); free_vars.extend(arm_free_vars);
} }
for var in with.iter() { for var in with_bnd.iter().flatten() {
free_vars.remove(var); free_vars.remove(var);
} }
let free_vars = free_vars.into_iter().collect::<Vec<_>>(); let free_vars = free_vars.into_iter().collect::<Vec<_>>();
@ -103,19 +103,16 @@ impl Term {
// Create the new function // Create the new function
let x_nam = Name::new("%x"); let x_nam = Name::new("%x");
let mut body = Term::Mat { let body = Term::Mat {
arg: Box::new(Term::Var { nam: x_nam.clone() }), arg: Box::new(Term::Var { nam: x_nam.clone() }),
bnd: None, 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), arms: std::mem::take(arms),
}; };
for nam in with.iter().rev() { let body = Term::rfold_lams(body, with_bnd.iter().cloned());
body = Term::lam(Pattern::Var(Some(nam.clone())), body); let body = Term::rfold_lams(body, free_vars.iter().map(|nam| Some(nam.clone())));
} let body = Term::lam(Pattern::Var(Some(x_nam)), 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 def = let def =
Definition { name: new_nam.clone(), rules: vec![Rule { pats: vec![], body }], builtin: false }; Definition { name: new_nam.clone(), rules: vec![Rule { pats: vec![], body }], builtin: false };
new_defs.push(def); new_defs.push(def);
@ -123,7 +120,7 @@ impl Term {
// Call the new function // Call the new function
let call = Term::call(Term::Ref { nam: new_nam.clone() }, [std::mem::take(arg.as_mut())]); 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, 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; *self = call;
} }
Ok(()) Ok(())

View File

@ -313,7 +313,9 @@ fn num_rule(
let default_body = simplify_rule_match(args.clone(), new_rules, default_with, ctrs, adts)?; let default_body = simplify_rule_match(args.clone(), new_rules, default_with, ctrs, adts)?;
// Linearize previously matched vars and current args. // 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 term = num_bodies.into_iter().enumerate().rfold(default_body, |term, (i, body)| {
let val = if i > 0 { let val = if i > 0 {
@ -328,7 +330,8 @@ fn num_rule(
Term::Swt { Term::Swt {
arg: Box::new(val), arg: Box::new(val),
bnd: Some(arg.clone()), bnd: Some(arg.clone()),
with: swt_with.clone(), with_bnd: with_bnd.clone(),
with_arg: with_arg.clone(),
pred: Some(pred_var.clone()), pred: Some(pred_var.clone()),
arms: vec![body, term], arms: vec![body, term],
} }
@ -448,12 +451,15 @@ fn switch_rule(
} }
// Linearize previously matched vars and current args. // 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 { let term = Term::Mat {
arg: Box::new(Term::Var { nam: arg.clone() }), arg: Box::new(Term::Var { nam: arg.clone() }),
bnd: Some(arg.clone()), bnd: Some(arg.clone()),
with: mat_with, with_bnd,
with_arg,
arms: new_arms, arms: new_arms,
}; };
Ok(term) Ok(term)

View File

@ -30,7 +30,8 @@ impl Term {
*self = Term::Mat { *self = Term::Mat {
arg: Box::new(Term::Var { nam: var.clone() }), arg: Box::new(Term::Var { nam: var.clone() }),
bnd: Some(std::mem::take(var)), bnd: Some(std::mem::take(var)),
with: vec![], with_bnd: vec![],
with_arg: vec![],
arms: vec![(Some(ctr.clone()), vec![], std::mem::take(bod))], arms: vec![(Some(ctr.clone()), vec![], std::mem::take(bod))],
} }
} else { } else {

View File

@ -52,7 +52,7 @@ fn encode_ctr_scott<'a>(
let ctr = Term::Var { nam: ctr_name.clone() }; let ctr = Term::Var { nam: ctr_name.clone() };
let app = Term::call(ctr, ctr_args.clone().cloned().map(|nam| Term::Var { nam })); 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)); 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 { fn encode_ctr_num_scott<'a>(ctr_args: impl DoubleEndedIterator<Item = &'a Name> + Clone, tag: &str) -> Term {

View File

@ -28,16 +28,18 @@ impl Term {
child.encode_matches(adt_encoding) child.encode_matches(adt_encoding)
} }
if let Term::Mat { arg, bnd: _, with, arms: rules } = self { if let Term::Mat { arg, bnd: _, with_bnd, with_arg, arms } = self {
assert!(with.is_empty()); assert!(with_bnd.is_empty());
assert!(with_arg.is_empty());
let arg = std::mem::take(arg.as_mut()); 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); *self = encode_match(arg, rules, adt_encoding);
} else if let Term::Swt { arg, bnd: _, with, pred, arms: rules } = self { } else if let Term::Swt { arg, bnd: _, with_bnd, with_arg, pred, arms } = self {
assert!(with.is_empty()); assert!(with_bnd.is_empty());
assert!(with_arg.is_empty());
let arg = std::mem::take(arg.as_mut()); let arg = std::mem::take(arg.as_mut());
let pred = std::mem::take(pred); let pred = std::mem::take(pred);
let rules = std::mem::take(rules); let rules = std::mem::take(arms);
*self = encode_switch(arg, pred, rules); *self = encode_switch(arg, pred, rules);
} }
}) })
@ -60,7 +62,8 @@ fn encode_match(arg: Term, rules: Vec<MatchRule>, adt_encoding: AdtEncoding) ->
Term::Swt { Term::Swt {
arg: Box::new(Term::Var { nam: Name::new("%tag") }), arg: Box::new(Term::Var { nam: Name::new("%tag") }),
bnd: None, bnd: None,
with: vec![], with_bnd: vec![],
with_arg: vec![],
pred: None, pred: None,
arms: vec![std::mem::take(arm), make_switches(rest)], 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 { let term = Term::Swt {
arg: Box::new(Term::Var { nam: Name::new("%tag") }), arg: Box::new(Term::Var { nam: Name::new("%tag") }),
bnd: None, bnd: None,
with: vec![], with_bnd: vec![],
with_arg: vec![],
pred: None, pred: None,
arms: vec![arm, Term::Era], 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)| { nums.iter_mut().enumerate().rfold(last_arm, |term, (i, rule)| {
let arms = vec![std::mem::take(rule), term]; let arms = vec![std::mem::take(rule), term];
if i == 0 { 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 { } else {
let swt = Term::Swt { let swt = Term::Swt {
arg: Box::new(Term::Var { nam: match_var.clone() }), arg: Box::new(Term::Var { nam: match_var.clone() }),
bnd: None, bnd: None,
with: vec![], with_bnd: vec![],
with_arg: vec![],
pred: None, pred: None,
arms, arms,
}; };

View File

@ -86,7 +86,8 @@ impl Term {
} }
// Add a use term to each arm rebuilding the matched variable // Add a use term to each arm rebuilding the matched variable
match self { 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 { for (ctr, fields, body) in arms {
if let Some(ctr) = ctr { if let Some(ctr) = ctr {
*body = Term::Use { *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; let n_nums = arms.len() - 1;
for (i, arm) in arms.iter_mut().enumerate() { for (i, arm) in arms.iter_mut().enumerate() {
let orig = if i == n_nums { 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) { 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!() unreachable!()
}; };
let bnd = bnd.clone().unwrap(); let bnd = bnd.clone().unwrap();

View File

@ -236,11 +236,11 @@ impl Term {
} }
})) }))
} }
Term::Mat { arg, bnd: _, with: _, arms } => { Term::Mat { arg, bnd: _, with_bnd: _, with_arg, arms } => FloatIter::Mat(
FloatIter::Mat([arg.as_mut()].into_iter().chain(arms.iter_mut().map(|r| &mut r.2))) [arg.as_mut()].into_iter().chain(with_arg.iter_mut()).chain(arms.iter_mut().map(|r| &mut r.2)),
} ),
Term::Swt { arg, bnd: _, with: _, pred: _, arms } => { Term::Swt { arg, bnd: _, with_bnd: _, with_arg, pred: _, arms } => {
FloatIter::Swt([arg.as_mut()].into_iter().chain(arms.iter_mut())) 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::Fan { els, .. } | Term::List { els } => FloatIter::Vec(els),
Term::Let { val: fst, nxt: snd, .. } Term::Let { val: fst, nxt: snd, .. }

View File

@ -80,22 +80,32 @@ impl Term {
}) })
} }
fn linearize_binds_single_match(&mut self, bind_terms: Vec<Term>) { fn linearize_binds_single_match(&mut self, mut bind_terms: Vec<Term>) {
let (used_vars, with, arms) = match self { let (used_vars, with_bnd, with_arg, arms) = match self {
Term::Mat { arg, bnd: _, with, arms } => { Term::Mat { arg, bnd: _, with_bnd, with_arg, arms } => {
let vars = arg.free_vars().into_keys().collect::<HashSet<_>>(); let vars = arg.free_vars().into_keys().collect::<HashSet<_>>();
let arms = arms.iter_mut().map(|arm| &mut arm.2).collect::<Vec<_>>(); 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 vars = arg.free_vars().into_keys().collect::<HashSet<_>>();
let arms = arms.iter_mut().collect(); let arms = arms.iter_mut().collect();
(vars, with, arms) (vars, with_bnd, with_arg, arms)
} }
_ => unreachable!(), _ => 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 // Add the linearized terms to the arms and recurse
for arm in arms { for arm in arms {
@ -107,18 +117,31 @@ impl Term {
let linearized_binds = linearized let linearized_binds = linearized
.iter() .iter()
.flat_map(|t| match t { .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, .. } => { Term::Use { nam, .. } => {
if let Some(nam) = nam { if let Some(nam) = nam {
vec![nam] vec![nam.clone()]
} else { } else {
vec![] vec![]
} }
} }
_ => unreachable!(), _ => unreachable!(),
}) })
.collect::<HashSet<_>>(); .collect::<BTreeSet<_>>();
with.retain(|w| !linearized_binds.contains(w)); 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 // Add the non-linearized terms back to before the match
self.wrap_with_bind_terms(non_linearized); 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 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 */ /* Linearize all used vars */
impl Book { impl Book {
@ -351,15 +392,17 @@ impl Term {
/// Obs: This does not modify unscoped variables. /// Obs: This does not modify unscoped variables.
pub fn lift_match_vars(match_term: &mut Term) -> &mut Term { pub fn lift_match_vars(match_term: &mut Term) -> &mut Term {
// Collect match arms with binds // Collect match arms with binds
let arms: Vec<_> = match match_term { let (with_bnd, with_arg, arms) = match match_term {
Term::Mat { arg: _, bnd: _, with: _, arms: rules } => { Term::Mat { arg: _, bnd: _, with_bnd, with_arg, arms: rules } => {
rules.iter().map(|(_, binds, body)| (binds.iter().flatten().cloned().collect(), body)).collect() 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 (succ, nums) = arms.split_last_mut().unwrap();
let mut arms = nums.iter().map(|body| (vec![], body)).collect::<Vec<_>>(); let mut arms = nums.iter().map(|body| (vec![], body)).collect::<Vec<_>>();
arms.push((vec![pred.clone().unwrap()], succ)); arms.push((vec![pred.clone().unwrap()], succ));
arms (with_bnd.clone(), with_arg.clone(), arms)
} }
_ => unreachable!(), _ => unreachable!(),
}; };
@ -380,27 +423,36 @@ pub fn lift_match_vars(match_term: &mut Term) -> &mut Term {
// Add lambdas to the arms // Add lambdas to the arms
match match_term { match match_term {
Term::Mat { arg: _, bnd: _, with, arms } => { Term::Mat { arg: _, bnd: _, with_bnd, with_arg, arms } => {
with.retain(|with| !vars_to_lift.contains(with)); update_with_clause(with_bnd, with_arg, &vars_to_lift);
for arm in arms { for arm in arms {
let old_body = std::mem::take(&mut arm.2); let old_body = std::mem::take(&mut arm.2);
arm.2 = arm.2 = Term::rfold_lams(old_body, vars_to_lift.iter().cloned().map(Some));
vars_to_lift.iter().cloned().rfold(old_body, |body, nam| Term::lam(Pattern::Var(Some(nam)), body));
} }
} }
Term::Swt { arg: _, bnd: _, with, pred: _, arms } => { Term::Swt { arg: _, bnd: _, with_bnd, with_arg, pred: _, arms } => {
with.retain(|with| !vars_to_lift.contains(with)); update_with_clause(with_bnd, with_arg, &vars_to_lift);
for arm in arms { for arm in arms {
let old_body = std::mem::take(arm); let old_body = std::mem::take(arm);
*arm = *arm = Term::rfold_lams(old_body, vars_to_lift.iter().cloned().map(Some));
vars_to_lift.iter().cloned().rfold(old_body, |body, nam| Term::lam(Pattern::Var(Some(nam)), body));
} }
} }
_ => unreachable!(), _ => unreachable!(),
} }
// Add apps to the match // 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) get_match_reference(match_term)
} }
@ -439,38 +491,23 @@ impl Term {
} }
}); });
match self { match self {
Term::Mat { arg: _, bnd: _, with, arms: rules } => { Term::Mat { arg: _, bnd: _, with_bnd, with_arg, arms } => {
// Linearize the vars in the `with` clause, but only the used ones. for rule in arms {
let with = retain_used_names(std::mem::take(with), rules.iter().map(|r| &r.2)); rule.2 = Term::rfold_lams(std::mem::take(&mut rule.2), with_bnd.clone().into_iter());
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));
} }
*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 } => { Term::Swt { arg: _, bnd: _, with_bnd, with_arg, pred: _, arms } => {
let with = retain_used_names(std::mem::take(with), arms.iter()); for rule in arms {
for arm in arms { *rule = Term::rfold_lams(std::mem::take(rule), with_bnd.clone().into_iter());
*arm = with
.iter()
.rfold(std::mem::take(arm), |bod, nam| Term::lam(Pattern::Var(Some(nam.clone())), bod));
} }
*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
}

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
fun::{Book, FanKind, Name, Pattern, Tag, Term}, fun::{Book, FanKind, Name, Pattern, Tag, Term},
maybe_grow, maybe_grow, multi_iterator,
}; };
use std::collections::HashMap; use std::collections::HashMap;
@ -120,3 +120,54 @@ fn dup_name(nam: &Name, uses: u64) -> Name {
Name::new(format!("{nam}_{uses}")) 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"),
}
}
}

View File

@ -34,26 +34,134 @@ pub struct UniqueNameGenerator {
impl UniqueNameGenerator { impl UniqueNameGenerator {
// Recursively assign an id to each variable in the term, then convert each id into a unique name. // 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) { 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::Var { nam } => *nam = self.use_var(nam),
Term::Mat { with, .. } | Term::Swt { with, .. } => {
for nam in with { Term::Mat { bnd, arg, with_bnd, with_arg, arms }
*nam = self.use_var(nam); | 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());
} }
} }
_ => {}
} Term::Let { pat, val, nxt } | Term::Ask { pat, val, nxt } => {
maybe_grow(|| { self.unique_names_in_term(val);
for (child, binds) in term.children_mut_with_binds_mut() { for bnd in pat.binds() {
let binds: Vec<_> = binds.collect(); self.push(bnd.as_ref());
for bind in binds.iter() {
self.push(bind.as_ref());
} }
self.unique_names_in_term(child); self.unique_names_in_term(nxt);
for bind in binds.into_iter().rev() { for bind in pat.binds_mut() {
*bind = self.pop(bind.as_ref()); *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"),
}) })
} }

View File

@ -57,31 +57,38 @@ impl Stmt {
*self = gen_get(self, substitutions); *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() { for arm in arms.iter_mut() {
arm.rgt.gen_map_get(id); arm.rgt.gen_map_get(id);
} }
if let Some(nxt) = nxt { if let Some(nxt) = nxt {
nxt.gen_map_get(id); 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() { if !substitutions.is_empty() {
*self = gen_get(self, substitutions); *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() { for arm in arms.iter_mut() {
arm.gen_map_get(id); arm.gen_map_get(id);
} }
if let Some(nxt) = nxt { if let Some(nxt) = nxt {
nxt.gen_map_get(id); 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() { if !substitutions.is_empty() {
*self = gen_get(self, substitutions); *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); step.gen_map_get(id);
base.gen_map_get(id); base.gen_map_get(id);
if let Some(nxt) = nxt { if let Some(nxt) = nxt {
@ -146,7 +153,7 @@ impl Expr {
Expr::Lam { bod, .. } => { Expr::Lam { bod, .. } => {
go(bod, substitutions, id); go(bod, substitutions, id);
} }
Expr::Bin { lhs, rhs, .. } => { Expr::Opr { lhs, rhs, .. } => {
go(lhs, substitutions, id); go(lhs, substitutions, id);
go(rhs, substitutions, id); go(rhs, substitutions, id);
} }
@ -155,24 +162,24 @@ impl Expr {
go(el, substitutions, id); go(el, substitutions, id);
} }
} }
Expr::Constructor { kwargs, .. } => { Expr::Ctr { kwargs, .. } => {
for (_, arg) in kwargs.iter_mut() { for (_, arg) in kwargs.iter_mut() {
go(arg, substitutions, id); go(arg, substitutions, id);
} }
} }
Expr::Comprehension { term, iter, cond, .. } => { Expr::LstMap { term, iter, cond, .. } => {
go(term, substitutions, id); go(term, substitutions, id);
go(iter, substitutions, id); go(iter, substitutions, id);
if let Some(cond) = cond { if let Some(cond) = cond {
go(cond, substitutions, id); go(cond, substitutions, id);
} }
} }
Expr::MapInit { entries } => { Expr::Map { entries } => {
for (_, entry) in entries { for (_, entry) in entries {
go(entry, substitutions, id); 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(); let mut substitutions = Substitutions::new();

View File

@ -9,7 +9,7 @@ use interner::global::GlobalString;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Expr { pub enum Expr {
// "*" // "*"
Eraser, Era,
// [a-zA-Z_]+ // [a-zA-Z_]+
Var { nam: Name }, Var { nam: Name },
// "$" [a-zA-Z_]+ // "$" [a-zA-Z_]+
@ -21,7 +21,7 @@ pub enum Expr {
// "lambda" {names}* ":" {bod} // "lambda" {names}* ":" {bod}
Lam { names: Vec<(Name, bool)>, bod: Box<Expr> }, Lam { names: Vec<(Name, bool)>, bod: Box<Expr> },
// {lhs} {op} {rhs} // {lhs} {op} {rhs}
Bin { op: Op, lhs: Box<Expr>, rhs: Box<Expr> }, Opr { op: Op, lhs: Box<Expr>, rhs: Box<Expr> },
// "\"" ... "\"" // "\"" ... "\""
Str { val: GlobalString }, Str { val: GlobalString },
// "[" ... "]" // "[" ... "]"
@ -31,11 +31,11 @@ pub enum Expr {
// "{" {els} "}" // "{" {els} "}"
Sup { els: Vec<Expr> }, Sup { els: Vec<Expr> },
// {name} "{" {kwargs} "}" // {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})? "]" // "[" {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} "}" // "{" {entries} "}"
MapInit { entries: Vec<(Expr, Expr)> }, Map { entries: Vec<(Expr, Expr)> },
// {map} "[" {key} "]" // {map} "[" {key} "]"
MapGet { nam: Name, key: Box<Expr> }, MapGet { nam: Name, key: Box<Expr> },
} }
@ -106,7 +106,9 @@ pub enum Stmt {
// <nxt>? // <nxt>?
Match { Match {
arg: Box<Expr>, arg: Box<Expr>,
bind: Option<Name>, bnd: Option<Name>,
with_bnd: Vec<Option<Name>>,
with_arg: Vec<Expr>,
arms: Vec<MatchArm>, arms: Vec<MatchArm>,
nxt: Option<Box<Stmt>>, nxt: Option<Box<Stmt>>,
}, },
@ -116,7 +118,9 @@ pub enum Stmt {
// <nxt>? // <nxt>?
Switch { Switch {
arg: Box<Expr>, arg: Box<Expr>,
bind: Option<Name>, bnd: Option<Name>,
with_bnd: Vec<Option<Name>>,
with_arg: Vec<Expr>,
arms: Vec<Stmt>, arms: Vec<Stmt>,
nxt: Option<Box<Stmt>>, nxt: Option<Box<Stmt>>,
}, },
@ -126,8 +130,8 @@ pub enum Stmt {
// {base} // {base}
// <nxt>? // <nxt>?
Bend { Bend {
bind: Vec<Option<Name>>, bnd: Vec<Option<Name>>,
init: Vec<Expr>, arg: Vec<Expr>,
cond: Box<Expr>, cond: Box<Expr>,
step: Box<Stmt>, step: Box<Stmt>,
base: Box<Stmt>, base: Box<Stmt>,
@ -139,8 +143,9 @@ pub enum Stmt {
// <nxt>? // <nxt>?
Fold { Fold {
arg: Box<Expr>, arg: Box<Expr>,
bind: Option<Name>, bnd: Option<Name>,
with: Vec<Name>, with_bnd: Vec<Option<Name>>,
with_arg: Vec<Expr>,
arms: Vec<MatchArm>, arms: Vec<MatchArm>,
nxt: Option<Box<Stmt>>, nxt: Option<Box<Stmt>>,
}, },

View File

@ -64,9 +64,9 @@ impl Stmt {
nxt.order_kwargs(book)?; nxt.order_kwargs(book)?;
} }
} }
Stmt::Bend { bind: _, init, cond, step, base, nxt } => { Stmt::Bend { bnd: _, arg, cond, step, base, nxt } => {
for init in init { for arg in arg {
init.order_kwargs(book)?; arg.order_kwargs(book)?;
} }
cond.order_kwargs(book)?; cond.order_kwargs(book)?;
step.order_kwargs(book)?; step.order_kwargs(book)?;
@ -126,7 +126,7 @@ impl Expr {
} }
} }
Expr::Lam { bod, .. } => bod.order_kwargs(book)?, Expr::Lam { bod, .. } => bod.order_kwargs(book)?,
Expr::Bin { lhs, rhs, .. } => { Expr::Opr { lhs, rhs, .. } => {
lhs.order_kwargs(book)?; lhs.order_kwargs(book)?;
rhs.order_kwargs(book)?; rhs.order_kwargs(book)?;
} }
@ -135,14 +135,14 @@ impl Expr {
el.order_kwargs(book)?; el.order_kwargs(book)?;
} }
} }
Expr::Comprehension { term, iter, cond, .. } => { Expr::LstMap { term, iter, cond, .. } => {
term.order_kwargs(book)?; term.order_kwargs(book)?;
iter.order_kwargs(book)?; iter.order_kwargs(book)?;
if let Some(cond) = cond { if let Some(cond) = cond {
cond.order_kwargs(book)?; 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) => { Some(names) => {
go_order_kwargs(&names, args, kwargs)?; go_order_kwargs(&names, args, kwargs)?;
for arg in args { for arg in args {
@ -151,13 +151,13 @@ impl Expr {
} }
_ => return Err(format!("Constructor '{name}' not found.")), _ => return Err(format!("Constructor '{name}' not found.")),
}, },
Expr::MapInit { entries } => { Expr::Map { entries } => {
for entry in entries { for entry in entries {
entry.1.order_kwargs(book)?; entry.1.order_kwargs(book)?;
} }
} }
Expr::MapGet { .. } Expr::MapGet { .. }
| Expr::Eraser | Expr::Era
| Expr::Var { .. } | Expr::Var { .. }
| Expr::Chn { .. } | Expr::Chn { .. }
| Expr::Num { .. } | Expr::Num { .. }

View File

@ -112,7 +112,7 @@ impl<'a> PyParser<'a> {
self.advance_one(); self.advance_one();
// Empty map // Empty map
if self.try_consume("}") { if self.try_consume("}") {
return Ok(Expr::MapInit { entries: vec![] }); return Ok(Expr::Map { entries: vec![] });
} }
let head = self.parse_expr(false)?; let head = self.parse_expr(false)?;
self.skip_trivia(); self.skip_trivia();
@ -148,7 +148,7 @@ impl<'a> PyParser<'a> {
// Era // Era
'*' => { '*' => {
self.advance_one(); self.advance_one();
Expr::Eraser Expr::Era
} }
// Number // Number
c if is_num_char(c) => { c if is_num_char(c) => {
@ -216,7 +216,7 @@ impl<'a> PyParser<'a> {
if self.starts_with("{") { if self.starts_with("{") {
if let Expr::Var { nam } = base { if let Expr::Var { nam } = base {
let kwargs = self.list_like(|p| p.data_kwarg(), "{", "}", ",", true, 0)?; 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 { } else {
return self.expected_spanned("Constructor name", ini_idx, end_idx); 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)?; let tail = self.list_like(|p| p.parse_map_entry(), "", "}", ",", true, 0)?;
entries.extend(tail); entries.extend(tail);
Ok(Expr::MapInit { entries }) Ok(Expr::Map { entries })
} }
fn parse_sup(&mut self, head: Expr) -> ParseResult<Expr> { 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)?)); cond = Some(Box::new(self.parse_expr(false)?));
} }
self.consume("]")?; 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 { } else {
// List // List
let mut head = vec![head]; let mut head = vec![head];
@ -368,7 +368,7 @@ impl<'a> PyParser<'a> {
if op.precedence() == prec { if op.precedence() == prec {
self.parse_oper()?; self.parse_oper()?;
let rhs = self.parse_infix_expr(prec + 1, inline)?; 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(); self.skip_trivia_inline();
} else { } else {
break; break;
@ -579,9 +579,9 @@ impl<'a> PyParser<'a> {
} }
fn parse_match(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> { 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.skip_trivia_inline();
self.consume_exactly(":")?; let (with_bnd, with_arg) = self.parse_with_clause()?;
self.consume_new_line()?; self.consume_new_line()?;
indent.enter_level(); indent.enter_level();
@ -596,10 +596,10 @@ impl<'a> PyParser<'a> {
indent.exit_level(); indent.exit_level();
if nxt_indent == *indent { if nxt_indent == *indent {
let (nxt, nxt_indent) = self.parse_statement(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)) Ok((stmt, nxt_indent))
} else { } 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)) 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)> { fn parse_match_case(&mut self, indent: &mut Indent) -> ParseResult<(MatchArm, Indent)> {
self.parse_keyword("case")?; self.parse_keyword("case")?;
self.skip_trivia_inline(); self.skip_trivia_inline();
@ -644,9 +666,9 @@ impl<'a> PyParser<'a> {
} }
fn parse_switch(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> { 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.skip_trivia_inline();
self.consume_exactly(":")?; let (with_bnd, with_arg) = self.parse_with_clause()?;
indent.enter_level(); indent.enter_level();
self.consume_indent_exactly(*indent)?; self.consume_indent_exactly(*indent)?;
@ -680,10 +702,10 @@ impl<'a> PyParser<'a> {
indent.exit_level(); indent.exit_level();
if nxt_indent == *indent { if nxt_indent == *indent {
let (nxt, nxt_indent) = self.parse_statement(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)) Ok((stmt, nxt_indent))
} else { } 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)) Ok((stmt, nxt_indent))
} }
} }
@ -722,22 +744,7 @@ impl<'a> PyParser<'a> {
// Actually identical to match, except the return // Actually identical to match, except the return
let (bind, arg) = self.parse_match_arg()?; let (bind, arg) = self.parse_match_arg()?;
self.skip_trivia_inline(); self.skip_trivia_inline();
let with = if self.try_parse_keyword("with") { let (with_bnd, with_arg) = self.parse_with_clause()?;
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(":")?;
self.consume_new_line()?; self.consume_new_line()?;
indent.enter_level(); indent.enter_level();
@ -752,10 +759,11 @@ impl<'a> PyParser<'a> {
indent.exit_level(); indent.exit_level();
if nxt_indent == *indent { if nxt_indent == *indent {
let (nxt, nxt_indent) = self.parse_statement(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)) Ok((stmt, nxt_indent))
} else { } 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)) Ok((stmt, nxt_indent))
} }
} }
@ -800,8 +808,8 @@ impl<'a> PyParser<'a> {
if nxt_indent == *indent { if nxt_indent == *indent {
let (nxt, nxt_indent) = self.parse_statement(indent)?; let (nxt, nxt_indent) = self.parse_statement(indent)?;
let stmt = Stmt::Bend { let stmt = Stmt::Bend {
bind, bnd: bind,
init, arg: init,
cond: Box::new(cond), cond: Box::new(cond),
step: Box::new(step), step: Box::new(step),
base: Box::new(base), base: Box::new(base),
@ -810,8 +818,8 @@ impl<'a> PyParser<'a> {
Ok((stmt, nxt_indent)) Ok((stmt, nxt_indent))
} else { } else {
let stmt = Stmt::Bend { let stmt = Stmt::Bend {
bind, bnd: bind,
init, arg: init,
cond: Box::new(cond), cond: Box::new(cond),
step: Box::new(step), step: Box::new(step),
base: Box::new(base), base: Box::new(base),

View File

@ -135,13 +135,14 @@ impl Stmt {
let term = fun::Term::Swt { let term = fun::Term::Swt {
arg: Box::new(cond.to_fun()), arg: Box::new(cond.to_fun()),
bnd: Some(Name::new("%pred")), bnd: Some(Name::new("%pred")),
with: Vec::new(), with_bnd: vec![],
with_arg: vec![],
pred: Some(Name::new("%pred-1")), pred: Some(Name::new("%pred-1")),
arms, arms,
}; };
wrap_nxt_assign_stmt(term, nxt, pat)? 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 arg = arg.to_fun();
let mut fun_arms = vec![]; let mut fun_arms = vec![];
let mut arms = arms.into_iter(); let mut arms = arms.into_iter();
@ -150,6 +151,7 @@ impl Stmt {
StmtToFun::Return(term) => (None, term), StmtToFun::Return(term) => (None, term),
StmtToFun::Assign(pat, term) => (Some(pat), 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)); fun_arms.push((fst.lft, vec![], fst_rgt));
for arm in arms { for arm in arms {
let (arm_pat, arm_rgt) = match arm.rgt.into_fun()? { 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)), (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)? 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 arg = arg.to_fun();
let mut fun_arms = vec![]; let mut fun_arms = vec![];
let mut arms = arms.into_iter(); let mut arms = arms.into_iter();
@ -182,6 +184,7 @@ impl Stmt {
StmtToFun::Return(term) => (None, term), StmtToFun::Return(term) => (None, term),
StmtToFun::Assign(pat, term) => (Some(pat), term), StmtToFun::Assign(pat, term) => (Some(pat), term),
}; };
let with_arg = with_arg.into_iter().map(Expr::to_fun).collect();
fun_arms.push(fst); fun_arms.push(fst);
for arm in arms { for arm in arms {
let (arm_pat, arm) = match arm.into_fun()? { let (arm_pat, arm) = match arm.into_fun()? {
@ -202,11 +205,11 @@ impl Stmt {
(None, None) => fun_arms.push(arm), (None, None) => fun_arms.push(arm),
} }
} }
let pred = Some(Name::new(format!("{}-{}", bind.clone().unwrap(), fun_arms.len() - 1))); let pred = Some(Name::new(format!("{}-{}", bnd.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 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)? 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 arg = arg.to_fun();
let mut fun_arms = vec![]; let mut fun_arms = vec![];
let mut arms = arms.into_iter(); let mut arms = arms.into_iter();
@ -216,6 +219,7 @@ impl Stmt {
StmtToFun::Assign(pat, term) => (Some(pat), term), StmtToFun::Assign(pat, term) => (Some(pat), term),
}; };
fun_arms.push((fst.lft, vec![], fst_rgt)); fun_arms.push((fst.lft, vec![], fst_rgt));
let with_arg = with_arg.into_iter().map(Expr::to_fun).collect();
for arm in arms { for arm in arms {
let (arm_pat, arm_rgt) = match arm.rgt.into_fun()? { let (arm_pat, arm_rgt) = match arm.rgt.into_fun()? {
StmtToFun::Return(term) => (None, term), StmtToFun::Return(term) => (None, term),
@ -235,11 +239,11 @@ impl Stmt {
(None, None) => fun_arms.push((arm.lft, vec![], arm_rgt)), (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)? wrap_nxt_assign_stmt(term, nxt, fst_pat)?
} }
Stmt::Bend { bind, init, cond, step, base, nxt } => { Stmt::Bend { bnd, arg, cond, step, base, nxt } => {
let init = init.into_iter().map(Expr::to_fun).collect(); let arg = arg.into_iter().map(Expr::to_fun).collect();
let cond = cond.to_fun(); let cond = cond.to_fun();
let (pat, step, base) = match (step.into_fun()?, base.into_fun()?) { let (pat, step, base) = match (step.into_fun()?, base.into_fun()?) {
(StmtToFun::Return(s), StmtToFun::Return(b)) => (None, s, b), (StmtToFun::Return(s), StmtToFun::Return(b)) => (None, s, b),
@ -259,7 +263,7 @@ impl Stmt {
} }
}; };
let term = 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)? wrap_nxt_assign_stmt(term, nxt, pat)?
} }
Stmt::With { typ, bod, nxt } => { Stmt::With { typ, bod, nxt } => {
@ -317,7 +321,7 @@ impl Stmt {
impl Expr { impl Expr {
pub fn to_fun(self) -> fun::Term { pub fn to_fun(self) -> fun::Term {
match self { match self {
Expr::Eraser => fun::Term::Era, Expr::Era => fun::Term::Era,
Expr::Var { nam } => fun::Term::Var { nam }, Expr::Var { nam } => fun::Term::Var { nam },
Expr::Chn { nam } => fun::Term::Link { nam }, Expr::Chn { nam } => fun::Term::Link { nam },
Expr::Num { val } => fun::Term::Num { val }, 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)) }), pat: Box::new(if link { fun::Pattern::Chn(name) } else { fun::Pattern::Var(Some(name)) }),
bod: Box::new(acc), 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()) } fun::Term::Oper { opr: op, fst: Box::new(lhs.to_fun()), snd: Box::new(rhs.to_fun()) }
} }
Expr::Str { val } => fun::Term::Str { val }, Expr::Str { val } => fun::Term::Str { val },
@ -346,12 +350,12 @@ impl Expr {
tag: fun::Tag::Auto, tag: fun::Tag::Auto,
els: els.into_iter().map(Self::to_fun).collect(), els: els.into_iter().map(Self::to_fun).collect(),
}, },
Expr::Constructor { name, args, kwargs } => { Expr::Ctr { name, args, kwargs } => {
assert!(kwargs.is_empty()); assert!(kwargs.is_empty());
let args = args.into_iter().map(Self::to_fun); let args = args.into_iter().map(Self::to_fun);
fun::Term::call(fun::Term::Ref { nam: name }, args) 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_TAIL: &str = "%iter.tail";
const ITER_HEAD: &str = "%iter.head"; const ITER_HEAD: &str = "%iter.head";
@ -363,7 +367,8 @@ impl Expr {
fun::Term::Swt { fun::Term::Swt {
arg: Box::new(cond.to_fun()), arg: Box::new(cond.to_fun()),
bnd: Some(Name::new("%comprehension")), bnd: Some(Name::new("%comprehension")),
with: vec![], with_bnd: vec![],
with_arg: vec![],
pred: Some(Name::new("%comprehension-1")), pred: Some(Name::new("%comprehension-1")),
arms: vec![fun::Term::Var { nam: Name::new(ITER_TAIL) }, cons_branch], arms: vec![fun::Term::Var { nam: Name::new(ITER_TAIL) }, cons_branch],
} }
@ -379,14 +384,15 @@ impl Expr {
fun::Term::Fold { fun::Term::Fold {
bnd: Some(Name::new("%iter")), bnd: Some(Name::new("%iter")),
arg: Box::new(iter.to_fun()), arg: Box::new(iter.to_fun()),
with: Vec::new(), with_bnd: vec![],
with_arg: vec![],
arms: vec![ arms: vec![
(Some(Name::new(LNIL)), vec![], fun::Term::r#ref(LNIL)), (Some(Name::new(LNIL)), vec![], fun::Term::r#ref(LNIL)),
(Some(Name::new(LCONS)), vec![], cons_branch), (Some(Name::new(LCONS)), vec![], cons_branch),
], ],
} }
} }
Expr::MapInit { entries } => map_init(entries), Expr::Map { entries } => map_init(entries),
Expr::MapGet { .. } => unreachable!(), Expr::MapGet { .. } => unreachable!(),
} }
} }

View File

@ -112,9 +112,8 @@ pub fn desugar_book(
ctx.check_unbound_vars()?; ctx.check_unbound_vars()?;
ctx.book.make_var_names_unique();
// Auto match linearization // Auto match linearization
ctx.book.make_var_names_unique();
match opts.linearize_matches { match opts.linearize_matches {
OptLevel::Disabled => (), OptLevel::Disabled => (),
OptLevel::Alt => ctx.book.linearize_match_binds(), OptLevel::Alt => ctx.book.linearize_match_binds(),

View File

@ -228,10 +228,14 @@ fn simplify_matches() {
ctx.set_entrypoint(); ctx.set_entrypoint();
ctx.book.encode_adts(AdtEncoding::NumScott); ctx.book.encode_adts(AdtEncoding::NumScott);
ctx.fix_match_defs()?; ctx.fix_match_defs()?;
ctx.desugar_open()?;
ctx.book.encode_builtins(); ctx.book.encode_builtins();
ctx.resolve_refs()?; ctx.resolve_refs()?;
ctx.desugar_match_defs()?; ctx.desugar_match_defs()?;
ctx.fix_match_terms()?; ctx.fix_match_terms()?;
ctx.desugar_bend()?;
ctx.desugar_fold()?;
ctx.desugar_do_blocks()?;
ctx.check_unbound_vars()?; ctx.check_unbound_vars()?;
ctx.book.make_var_names_unique(); ctx.book.make_var_names_unique();
ctx.book.linearize_match_binds(); ctx.book.linearize_match_binds();
@ -273,10 +277,14 @@ fn encode_pattern_match() {
ctx.set_entrypoint(); ctx.set_entrypoint();
ctx.book.encode_adts(adt_encoding); ctx.book.encode_adts(adt_encoding);
ctx.fix_match_defs()?; ctx.fix_match_defs()?;
ctx.desugar_open()?;
ctx.book.encode_builtins(); ctx.book.encode_builtins();
ctx.resolve_refs()?; ctx.resolve_refs()?;
ctx.desugar_match_defs()?; ctx.desugar_match_defs()?;
ctx.fix_match_terms()?; ctx.fix_match_terms()?;
ctx.desugar_bend()?;
ctx.desugar_fold()?;
ctx.desugar_do_blocks()?;
ctx.check_unbound_vars()?; ctx.check_unbound_vars()?;
ctx.book.make_var_names_unique(); ctx.book.make_var_names_unique();
ctx.book.linearize_match_binds(); ctx.book.linearize_match_binds();

View File

@ -1,5 +1,5 @@
type Either = (Left value) | (Right value) 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/False) = 1
Foo (Either/Left Bool/False) (Either/Left Bool/True) = 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/False) (Either/Left Bool/True) = 3
Foo (Either/Right Bool/True) (Either/Left Bool/False) = 3 Foo (Either/Right Bool/True) (Either/Left Bool/False) = 3
Foo (Either/Right Bool/True) (Either/Left Bool/True) = 3 Foo (Either/Right Bool/True) (Either/Left Bool/True) = 3

View 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)

View File

@ -5,13 +5,13 @@ input_file: tests/golden_tests/encode_pattern_match/bool.bend
Scott Scott
(not) = λa (a bool/false bool/true) (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 (bool/true) = λa λ* a
@ -20,13 +20,13 @@ Scott
NumScott NumScott
(not) = λa (a λb switch b { 0: bool/false; _: λ* bool/true; }) (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) (bool/true) = λa (a bool/true/tag)

View File

@ -3,7 +3,7 @@ source: tests/golden_tests.rs
input_file: tests/golden_tests/encode_pattern_match/concat_def.bend input_file: tests/golden_tests/encode_pattern_match/concat_def.bend
--- ---
Scott 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))) (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) (String/Cons) = λa λb λ* λd (d a b)
NumScott 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))) (main) = (concat (String/Cons 97 (String/Cons 98 String/Nil)) (String/Cons 99 (String/Cons 100 String/Nil)))

View File

@ -3,31 +3,31 @@ source: tests/golden_tests.rs
input_file: tests/golden_tests/encode_pattern_match/definition_merge.bend input_file: tests/golden_tests/encode_pattern_match/definition_merge.bend
--- ---
Scott 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/Left) = λa λb λ* (b a)
(Either/Right) = λa λ* λc (c 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 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/Left) = λa λb (b Either/Left/tag a)
(Either/Right) = λa λb (b Either/Right/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/Left/tag) = 0
(Either/Right/tag) = 1 (Either/Right/tag) = 1
(Bool/Bool/True/tag) = 0 (Bool/True/tag) = 0
(Bool/Bool/False/tag) = 1 (Bool/False/tag) = 1

View File

@ -7,7 +7,7 @@ Scott
(Fn2) = λa let (*, c) = a; let (*, e) = c; let (f, *) = e; f (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) (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 (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) (main) = (Fn2 ((1, 2), (3, (4, (5, 6)))) 0)

View File

@ -3,11 +3,11 @@ source: tests/golden_tests.rs
input_file: tests/golden_tests/encode_pattern_match/list_merge_sort.bend input_file: tests/golden_tests/encode_pattern_match/list_merge_sort.bend
--- ---
Scott 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) (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)) (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) (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 (Bool/True) = λa λ* a
@ -26,11 +26,11 @@ Scott
(List_/Nil) = λ* λb b (List_/Nil) = λ* λb b
NumScott 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) (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)) (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) (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) (Bool/True) = λa (a Bool/True/tag)

View 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]

View File

@ -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; } (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 (Rule6) = λa a

View File

@ -2,7 +2,7 @@
source: tests/golden_tests.rs source: tests/golden_tests.rs
input_file: tests/golden_tests/simplify_matches/double_unwrap_box.bend 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) (Main) = (DoubleUnbox (Boxed/Box (Boxed/Box 0)) 5)

View File

@ -2,7 +2,7 @@
source: tests/golden_tests.rs source: tests/golden_tests.rs
input_file: tests/golden_tests/simplify_matches/double_unwrap_maybe.bend 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) (Main) = (DoubleUnwrap (Maybe/Some Maybe/None) 5)

View File

@ -2,7 +2,7 @@
source: tests/golden_tests.rs source: tests/golden_tests.rs
input_file: tests/golden_tests/simplify_matches/flatten_with_terminal.bend 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)) (main) = (Foo 2 (A_t/A B_t/B))

View File

@ -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); } (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); } (A2) = λa match a { ConsList/Cons b c: λd λe (b c d e); ConsList/Nil: λf λg (f g); }

View File

@ -2,6 +2,6 @@
source: tests/golden_tests.rs source: tests/golden_tests.rs
input_file: tests/golden_tests/simplify_matches/redundant_with_era.bend 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) = * (main) = *