From e5fe6b7fef992dfb4a141737750a84c69b8f70b3 Mon Sep 17 00:00:00 2001 From: Nicolas Abril Date: Thu, 7 Mar 2024 15:10:22 +0100 Subject: [PATCH] [sc-489] Implement Clone for AST iterators, refactor some code using it. Add some doc comments --- src/term/check/unbound_vars.rs | 8 +- src/term/mod.rs | 344 ++++++++++-------- src/term/parser/parser.rs | 2 +- .../transform/desugar_implicit_match_binds.rs | 26 +- src/term/transform/encode_adts.rs | 20 +- src/term/transform/encode_pattern_matching.rs | 22 +- src/term/transform/linearize_matches.rs | 4 +- src/term/transform/resolve_refs.rs | 9 +- src/term/transform/simplify_matches.rs | 2 +- src/term/util.rs | 56 --- 10 files changed, 246 insertions(+), 247 deletions(-) delete mode 100644 src/term/util.rs diff --git a/src/term/check/unbound_vars.rs b/src/term/check/unbound_vars.rs index 998a7e999..a6bc00982 100644 --- a/src/term/check/unbound_vars.rs +++ b/src/term/check/unbound_vars.rs @@ -40,7 +40,7 @@ impl Ctx<'_> { for rule in &mut def.rules { let mut scope = HashMap::new(); for pat in &rule.pats { - pat.named_binds().for_each(|nam| push_scope(Some(nam), &mut scope)); + pat.binds().for_each(|nam| push_scope(nam.as_ref(), &mut scope)); } rule.body.check_unbound_vars(&mut scope, &mut errs); @@ -101,13 +101,11 @@ pub fn check_uses<'a>( _ => { for (child, binds) in term.children_mut_with_binds() { - let binds: Vec<_> = binds.collect(); - - for bind in binds.iter() { + for bind in binds.clone() { push_scope(bind.as_ref(), scope); } check_uses(child, scope, globals, errs); - for bind in binds.iter().rev() { + for bind in binds.rev() { pop_scope(bind.as_ref(), scope); } } diff --git a/src/term/mod.rs b/src/term/mod.rs index ac7231b03..1bd5cc8ce 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -1,4 +1,4 @@ -use self::{check::type_check::infer_match_arg_type, parser::lexer::STRINGS, util::ChildrenIter}; +use self::{check::type_check::infer_match_arg_type, parser::lexer::STRINGS}; use crate::{diagnostics::Info, term::builtins::*, ENTRY_POINT}; use indexmap::{IndexMap, IndexSet}; use interner::global::GlobalString; @@ -17,7 +17,6 @@ pub mod net_to_term; pub mod parser; pub mod term_to_net; pub mod transform; -mod util; pub use net_to_term::{net_to_term, ReadbackError}; pub use term_to_net::{book_to_nets, term_to_compat_net}; @@ -215,6 +214,37 @@ pub enum AdtEncoding { #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Name(GlobalString); +/* Implementations */ + +/// A macro for creating iterators that can have statically known +/// different types. Useful for iterating over tree children, where +/// each tree node variant yields a different iterator type. +macro_rules! multi_iterator { + ($Iter:ident { $($Variant:ident),* $(,)? }) => { + #[derive(Debug, Clone)] + enum $Iter<$($Variant),*> { + $($Variant($Variant)),* + } + + impl),*> Iterator for $Iter<$($Variant),*> { + type Item = T; + fn next(&mut self) -> Option { + match self { $($Iter::$Variant(x) => x.next()),* } + } + + fn size_hint(&self) -> (usize, Option) { + match self { $($Iter::$Variant(x) => x.size_hint()),* } + } + } + + impl),*> DoubleEndedIterator for $Iter<$($Variant),*> { + fn next_back(&mut self) -> Option { + match self { $($Iter::$Variant(x) => x.next_back()),* } + } + } + }; +} + impl PartialEq for Name { fn eq(&self, other: &str) -> bool { &**self == other @@ -339,8 +369,8 @@ impl Term { Term::Lam { tag: Tag::Static, nam: None, bod: Box::new(bod) } } - pub fn tagged_lam(tag: Tag, nam: Name, bod: Term) -> Self { - Term::Lam { tag, nam: Some(nam), bod: Box::new(bod) } + pub fn tagged_lam(tag: Tag, nam: Option, bod: Term) -> Self { + Term::Lam { tag, nam, bod: Box::new(bod) } } pub fn var_or_era(nam: Option) -> Self { @@ -400,49 +430,45 @@ impl Term { } /* Iterators */ - pub fn children(&self) -> impl DoubleEndedIterator { + pub fn children(&self) -> impl DoubleEndedIterator + Clone { + multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat }); match self { - Term::Mat { args, rules } => { - ChildrenIter::Many(Box::new(args.iter().chain(rules.iter().map(|r| &r.body)))) - } - Term::Tup { els } | Term::Sup { els, .. } | Term::Lst { els } => { - ChildrenIter::Many(Box::new(els.iter())) - } + Term::Mat { args, rules } => ChildrenIter::Mat(args.iter().chain(rules.iter().map(|r| &r.body))), + Term::Tup { els } | Term::Sup { els, .. } | Term::Lst { els } => ChildrenIter::Vec(els.iter()), Term::Let { val: fst, nxt: snd, .. } | Term::App { fun: fst, arg: snd, .. } | Term::Dup { val: fst, nxt: snd, .. } - | Term::Opx { fst, snd, .. } => ChildrenIter::two(fst.as_ref(), snd.as_ref()), - Term::Lam { bod, .. } | Term::Chn { bod, .. } => ChildrenIter::one(bod.as_ref()), + | Term::Opx { fst, snd, .. } => ChildrenIter::Two([fst.as_ref(), snd.as_ref()].into_iter()), + Term::Lam { bod, .. } | Term::Chn { bod, .. } => ChildrenIter::One([bod.as_ref()].into_iter()), Term::Var { .. } | Term::Lnk { .. } | Term::Num { .. } | Term::Str { .. } | Term::Ref { .. } | Term::Era - | Term::Err => ChildrenIter::zero(), + | Term::Err => ChildrenIter::Zero([].into_iter()), } } pub fn children_mut(&mut self) -> impl DoubleEndedIterator { + multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat }); match self { Term::Mat { args, rules } => { - ChildrenIter::Many(Box::new(args.iter_mut().chain(rules.iter_mut().map(|r| &mut r.body)))) - } - Term::Tup { els } | Term::Sup { els, .. } | Term::Lst { els } => { - ChildrenIter::Many(Box::new(els.iter_mut())) + ChildrenIter::Mat(args.iter_mut().chain(rules.iter_mut().map(|r| &mut r.body))) } + Term::Tup { els } | Term::Sup { els, .. } | Term::Lst { els } => ChildrenIter::Vec(els.iter_mut()), Term::Let { val: fst, nxt: snd, .. } | Term::App { fun: fst, arg: snd, .. } | Term::Dup { val: fst, nxt: snd, .. } - | Term::Opx { fst, snd, .. } => ChildrenIter::two(fst.as_mut(), snd.as_mut()), - Term::Lam { bod, .. } | Term::Chn { bod, .. } => ChildrenIter::one(bod.as_mut()), + | Term::Opx { fst, snd, .. } => ChildrenIter::Two([fst.as_mut(), snd.as_mut()].into_iter()), + Term::Lam { bod, .. } | Term::Chn { bod, .. } => ChildrenIter::One([bod.as_mut()].into_iter()), Term::Var { .. } | Term::Lnk { .. } | Term::Num { .. } | Term::Str { .. } | Term::Ref { .. } | Term::Era - | Term::Err => ChildrenIter::zero(), + | Term::Err => ChildrenIter::Zero([].into_iter()), } } @@ -454,67 +480,80 @@ impl Term { /// many binds for the next term. pub fn children_with_binds( &self, - ) -> impl DoubleEndedIterator>)> { + ) -> impl DoubleEndedIterator> + Clone)> + Clone + { + multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat }); + multi_iterator!(BindsIter { Zero, One, Dup, Pat, Rule }); match self { - Term::Mat { args, rules } => ChildrenIter::Many(Box::new( - args.iter().map(|arg| (arg, ChildrenIter::zero())).chain( - rules - .iter() - .map(|r| (&r.body, ChildrenIter::Many(Box::new(r.pats.iter().flat_map(|p| p.binds()))))), - ), - )), + Term::Mat { args, rules } => ChildrenIter::Mat( + args + .iter() + .map(|arg| (arg, BindsIter::Zero([].into_iter()))) + .chain(rules.iter().map(|r| (&r.body, BindsIter::Rule(r.pats.iter().flat_map(|p| p.binds()))))), + ), Term::Tup { els } | Term::Sup { els, .. } | Term::Lst { els } => { - ChildrenIter::Many(Box::new(els.iter().map(|el| (el, ChildrenIter::zero())))) + ChildrenIter::Vec(els.iter().map(|el| (el, BindsIter::Zero([].into_iter())))) } - Term::Dup { bnd, val, nxt, .. } => ChildrenIter::two( - (val.as_ref(), ChildrenIter::zero()), - (nxt.as_ref(), ChildrenIter::Many(Box::new(bnd.iter()))), + Term::Let { pat, val, nxt, .. } => ChildrenIter::Two( + [(val.as_ref(), BindsIter::Zero([].into_iter())), (nxt.as_ref(), BindsIter::Pat(pat.binds()))] + .into_iter(), + ), + Term::Dup { bnd, val, nxt, .. } => ChildrenIter::Two( + [(val.as_ref(), BindsIter::Zero([].into_iter())), (nxt.as_ref(), BindsIter::Dup(bnd.iter()))] + .into_iter(), ), - Term::Let { pat, val, nxt, .. } => ChildrenIter::two( - (val.as_ref(), ChildrenIter::zero()), - (nxt.as_ref(), ChildrenIter::Many(Box::new(pat.binds()))), + Term::App { fun: fst, arg: snd, .. } | Term::Opx { fst, snd, .. } => ChildrenIter::Two( + [(fst.as_ref(), BindsIter::Zero([].into_iter())), (snd.as_ref(), BindsIter::Zero([].into_iter()))] + .into_iter(), ), - Term::App { fun: fst, arg: snd, .. } | Term::Opx { fst, snd, .. } => { - ChildrenIter::two((fst.as_ref(), ChildrenIter::zero()), (snd.as_ref(), ChildrenIter::zero())) + Term::Lam { nam, bod, .. } => { + ChildrenIter::One([(bod.as_ref(), BindsIter::One([nam].into_iter()))].into_iter()) + } + Term::Chn { bod, .. } => { + ChildrenIter::One([(bod.as_ref(), BindsIter::Zero([].into_iter()))].into_iter()) } - Term::Lam { nam, bod, .. } => ChildrenIter::one((bod.as_ref(), ChildrenIter::one(nam))), - Term::Chn { bod, .. } => ChildrenIter::one((bod.as_ref(), ChildrenIter::zero())), Term::Var { .. } | Term::Lnk { .. } | Term::Num { .. } | Term::Str { .. } | Term::Ref { .. } | Term::Era - | Term::Err => ChildrenIter::zero(), + | Term::Err => ChildrenIter::Zero([].into_iter()), } } pub fn children_mut_with_binds( &mut self, - ) -> impl DoubleEndedIterator>)> { + ) -> impl DoubleEndedIterator> + Clone)> + { + multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat }); + multi_iterator!(BindsIter { Zero, One, Dup, Pat, Rule }); match self { - Term::Mat { args, rules } => ChildrenIter::Many(Box::new( - args.iter_mut().map(|arg| (arg, ChildrenIter::zero())).chain( - rules - .iter_mut() - .map(|r| (&mut r.body, ChildrenIter::Many(Box::new(r.pats.iter().flat_map(|p| p.binds()))))), - ), - )), - Term::Let { pat, val, nxt, .. } => ChildrenIter::two( - (val.as_mut(), ChildrenIter::zero()), - (nxt.as_mut(), ChildrenIter::Many(Box::new(pat.binds()))), + Term::Mat { args, rules } => { + ChildrenIter::Mat(args.iter_mut().map(|arg| (arg, BindsIter::Zero([].into_iter()))).chain( + rules.iter_mut().map(|r| (&mut r.body, BindsIter::Rule(r.pats.iter().flat_map(|p| p.binds())))), + )) + } + Term::Tup { els } | Term::Sup { els, .. } | Term::Lst { els } => { + ChildrenIter::Vec(els.iter_mut().map(|el| (el, BindsIter::Zero([].into_iter())))) + } + Term::Let { pat, val, nxt, .. } => ChildrenIter::Two( + [(val.as_mut(), BindsIter::Zero([].into_iter())), (nxt.as_mut(), BindsIter::Pat(pat.binds()))] + .into_iter(), ), - Term::Dup { bnd, val, nxt, .. } => ChildrenIter::two( - (val.as_mut(), ChildrenIter::zero()), - (nxt.as_mut(), ChildrenIter::Many(Box::new(bnd.iter()))), + Term::Dup { bnd, val, nxt, .. } => ChildrenIter::Two( + [(val.as_mut(), BindsIter::Zero([].into_iter())), (nxt.as_mut(), BindsIter::Dup(bnd.iter()))] + .into_iter(), ), - Term::Tup { els } | Term::Sup { els, .. } | Term::Lst { els } => { - ChildrenIter::Many(Box::new(els.iter_mut().map(|el| (el, ChildrenIter::zero())))) + Term::App { fun: fst, arg: snd, .. } | Term::Opx { fst, snd, .. } => ChildrenIter::Two( + [(fst.as_mut(), BindsIter::Zero([].into_iter())), (snd.as_mut(), BindsIter::Zero([].into_iter()))] + .into_iter(), + ), + Term::Lam { nam, bod, .. } => { + ChildrenIter::One([(bod.as_mut(), BindsIter::One([&*nam].into_iter()))].into_iter()) } - Term::Lam { nam, bod, .. } => ChildrenIter::one((bod.as_mut(), ChildrenIter::one(&*nam))), - Term::Chn { bod, .. } => ChildrenIter::one((bod.as_mut(), ChildrenIter::zero())), - Term::App { fun: fst, arg: snd, .. } | Term::Opx { fst, snd, .. } => { - ChildrenIter::two((fst.as_mut(), ChildrenIter::zero()), (snd.as_mut(), ChildrenIter::zero())) + Term::Chn { bod, .. } => { + ChildrenIter::One([(bod.as_mut(), BindsIter::Zero([].into_iter()))].into_iter()) } Term::Var { .. } | Term::Lnk { .. } @@ -522,34 +561,43 @@ impl Term { | Term::Str { .. } | Term::Ref { .. } | Term::Era - | Term::Err => ChildrenIter::zero(), + | Term::Err => ChildrenIter::Zero([].into_iter()), } } pub fn children_mut_with_binds_mut( &mut self, ) -> impl DoubleEndedIterator>)> { + multi_iterator!(ChildrenIter { Zero, One, Two, Vec, Mat }); + multi_iterator!(BindsIter { Zero, One, Dup, Pat, Rule }); match self { - Term::Mat { args, rules } => ChildrenIter::Many(Box::new( - args.iter_mut().map(|arg| (arg, ChildrenIter::zero())).chain(rules.iter_mut().map(|r| { - (&mut r.body, ChildrenIter::Many(Box::new(r.pats.iter_mut().flat_map(|p| p.binds_mut())))) - })), - )), - Term::Let { pat, val, nxt, .. } => ChildrenIter::two( - (val.as_mut(), ChildrenIter::zero()), - (nxt.as_mut(), ChildrenIter::Many(Box::new(pat.binds_mut()))), - ), - Term::Dup { bnd, val, nxt, .. } => ChildrenIter::two( - (val.as_mut(), ChildrenIter::zero()), - (nxt.as_mut(), ChildrenIter::Many(Box::new(bnd.iter_mut()))), + Term::Mat { args, rules } => ChildrenIter::Mat( + args.iter_mut().map(|arg| (arg, BindsIter::Zero([].into_iter()))).chain( + rules + .iter_mut() + .map(|r| (&mut r.body, BindsIter::Rule(r.pats.iter_mut().flat_map(|p| p.binds_mut())))), + ), ), - Term::Lam { nam, bod, .. } => ChildrenIter::one((bod.as_mut(), ChildrenIter::one(nam))), - Term::Chn { bod, .. } => ChildrenIter::one((bod.as_mut(), ChildrenIter::zero())), Term::Tup { els } | Term::Sup { els, .. } | Term::Lst { els } => { - ChildrenIter::Many(Box::new(els.iter_mut().map(|el| (el, ChildrenIter::zero())))) + ChildrenIter::Vec(els.iter_mut().map(|el| (el, BindsIter::Zero([].into_iter())))) + } + Term::Let { pat, val, nxt, .. } => ChildrenIter::Two( + [(val.as_mut(), BindsIter::Zero([].into_iter())), (nxt.as_mut(), BindsIter::Pat(pat.binds_mut()))] + .into_iter(), + ), + Term::Dup { bnd, val, nxt, .. } => ChildrenIter::Two( + [(val.as_mut(), BindsIter::Zero([].into_iter())), (nxt.as_mut(), BindsIter::Dup(bnd.iter_mut()))] + .into_iter(), + ), + Term::App { fun: fst, arg: snd, .. } | Term::Opx { fst, snd, .. } => ChildrenIter::Two( + [(fst.as_mut(), BindsIter::Zero([].into_iter())), (snd.as_mut(), BindsIter::Zero([].into_iter()))] + .into_iter(), + ), + Term::Lam { nam, bod, .. } => { + ChildrenIter::One([(bod.as_mut(), BindsIter::One([nam].into_iter()))].into_iter()) } - Term::App { fun: fst, arg: snd, .. } | Term::Opx { fst, snd, .. } => { - ChildrenIter::two((fst.as_mut(), ChildrenIter::zero()), (snd.as_mut(), ChildrenIter::zero())) + Term::Chn { bod, .. } => { + ChildrenIter::One([(bod.as_mut(), BindsIter::Zero([].into_iter()))].into_iter()) } Term::Var { .. } | Term::Lnk { .. } @@ -557,14 +605,15 @@ impl Term { | Term::Str { .. } | Term::Ref { .. } | Term::Era - | Term::Err => ChildrenIter::zero(), + | Term::Err => ChildrenIter::Zero([].into_iter()), } } - pub fn patterns(&self) -> impl DoubleEndedIterator { + pub fn patterns(&self) -> impl DoubleEndedIterator + Clone { + multi_iterator!(PatternsIter { Zero, Let, Mat }); match self { - Term::Mat { rules, .. } => ChildrenIter::Many(Box::new(rules.iter().flat_map(|r| r.pats.iter()))), - Term::Let { pat, .. } => ChildrenIter::One([pat].into_iter()), + Term::Mat { rules, .. } => PatternsIter::Mat(rules.iter().flat_map(|r| r.pats.iter())), + Term::Let { pat, .. } => PatternsIter::Let([pat].into_iter()), Term::Tup { .. } | Term::Sup { .. } | Term::Lst { .. } @@ -579,32 +628,30 @@ impl Term { | Term::Str { .. } | Term::Ref { .. } | Term::Era - | Term::Err => ChildrenIter::zero(), + | Term::Err => PatternsIter::Zero([].into_iter()), } } pub fn patterns_mut(&mut self) -> impl DoubleEndedIterator { + multi_iterator!(PatternsIter { Zero, Let, Mat }); match self { - Term::Mat { rules, .. } => { - ChildrenIter::Many(Box::new(rules.iter_mut().flat_map(|r| r.pats.iter_mut()))) - } - Term::Let { pat, .. } => ChildrenIter::One([pat].into_iter()), - - Term::Lam { .. } - | Term::Var { .. } + Term::Mat { rules, .. } => PatternsIter::Mat(rules.iter_mut().flat_map(|r| r.pats.iter_mut())), + Term::Let { pat, .. } => PatternsIter::Let([pat].into_iter()), + Term::Tup { .. } + | Term::Sup { .. } + | Term::Lst { .. } + | Term::Dup { .. } + | Term::App { .. } + | Term::Opx { .. } + | Term::Lam { .. } | Term::Chn { .. } + | Term::Var { .. } | Term::Lnk { .. } - | Term::App { .. } - | Term::Tup { .. } - | Term::Dup { .. } - | Term::Sup { .. } | Term::Num { .. } | Term::Str { .. } - | Term::Lst { .. } - | Term::Opx { .. } | Term::Ref { .. } | Term::Era - | Term::Err => ChildrenIter::zero(), + | Term::Err => PatternsIter::Zero([].into_iter()), } } @@ -635,15 +682,15 @@ impl Term { /// Substitute the occurrence of an unscoped variable with the given term. pub fn subst_unscoped(&mut self, from: &Name, to: &Term) { - Term::recursive_call(move || match self { - Term::Lnk { nam } if nam == from => { + Term::recursive_call(move || { + if let Term::Lnk { nam } = self + && nam == from + { *self = to.clone(); } - _ => { - for child in self.children_mut() { - child.subst_unscoped(from, to); - } + for child in self.children_mut() { + child.subst_unscoped(from, to); } }) } @@ -652,20 +699,20 @@ impl Term { /// and the number of times each var is used pub fn free_vars(&self) -> HashMap { fn go(term: &Term, free_vars: &mut HashMap) { - Term::recursive_call(move || match term { - Term::Var { nam } => *free_vars.entry(nam.clone()).or_default() += 1, - - _ => { - for (child, binds) in term.children_with_binds() { - let mut new_scope = Default::default(); - go(child, &mut new_scope); + Term::recursive_call(move || { + if let Term::Var { nam } = term { + *free_vars.entry(nam.clone()).or_default() += 1; + } - for nam in binds.flatten() { - new_scope.remove(nam); - } + for (child, binds) in term.children_with_binds() { + let mut new_scope = Default::default(); + go(child, &mut new_scope); - free_vars.extend(new_scope); + for nam in binds.flatten() { + new_scope.remove(nam); } + + free_vars.extend(new_scope); } }) } @@ -678,21 +725,19 @@ impl Term { /// Returns the set of declared and the set of used unscoped variables pub fn unscoped_vars(&self) -> (IndexSet, IndexSet) { fn go(term: &Term, decls: &mut IndexSet, uses: &mut IndexSet) { - Term::recursive_call(move || match term { - Term::Chn { tag: _, nam, bod } => { - if let Some(nam) = nam { + Term::recursive_call(move || { + match term { + Term::Chn { nam: Some(nam), .. } => { decls.insert(nam.clone()); } - go(bod, decls, uses); - } - Term::Lnk { nam } => { - uses.insert(nam.clone()); + Term::Lnk { nam } => { + uses.insert(nam.clone()); + } + _ => {} } - _ => { - for child in term.children() { - go(child, decls, uses); - } + for child in term.children() { + go(child, decls, uses); } }) } @@ -809,49 +854,32 @@ impl Pattern { pub fn binds_mut(&mut self) -> impl DoubleEndedIterator> { // Can't have a Pattern::iter_mut() since it has a tree-like structure. - fn go<'a>(pat: &'a mut Pattern, set: &mut Vec<&'a mut Option>) { + let mut binds = vec![]; + let mut to_visit = vec![self]; + while let Some(pat) = to_visit.pop() { match pat { - Pattern::Var(nam) => set.push(nam), - Pattern::Ctr(_, pats) | Pattern::Lst(pats) | Pattern::Tup(pats) => { - pats.iter_mut().for_each(|pat| go(pat, set)) - } - Pattern::Num(NumCtr::Succ(_, Some(nam))) => { - set.push(nam); - } - Pattern::Num(_) => {} - Pattern::Str(_) => {} + Pattern::Var(nam) | Pattern::Num(NumCtr::Succ(_, Some(nam))) => binds.push(nam), + _ => to_visit.extend(pat.children_mut().rev()), } } - let mut set = Vec::new(); - go(self, &mut set); - set.into_iter() - } - - pub fn named_binds(&self) -> impl DoubleEndedIterator + Clone { - self.binds().flatten() - } - - pub fn named_binds_mut(&mut self) -> impl DoubleEndedIterator { - self.binds_mut().flatten() + binds.into_iter() } /// Returns an iterator over each immediate child sub-pattern of `self`. /// Considers Lists as its own pattern and not a sequence of Cons. - pub fn children(&self) -> ChildrenIter<&Pattern> { + pub fn children(&self) -> impl DoubleEndedIterator + Clone { + multi_iterator!(ChildrenIter { Zero, Vec }); match self { - Pattern::Ctr(_, els) | Pattern::Tup(els) | Pattern::Lst(els) => { - ChildrenIter::Many(Box::new(els.iter())) - } - Pattern::Var(_) | Pattern::Num(_) | Pattern::Str(_) => ChildrenIter::zero(), + Pattern::Ctr(_, els) | Pattern::Tup(els) | Pattern::Lst(els) => ChildrenIter::Vec(els.iter()), + Pattern::Var(_) | Pattern::Num(_) | Pattern::Str(_) => ChildrenIter::Zero([].into_iter()), } } - pub fn children_mut(&mut self) -> ChildrenIter<&mut Pattern> { + pub fn children_mut(&mut self) -> impl DoubleEndedIterator { + multi_iterator!(ChildrenIter { Zero, Vec }); match self { - Pattern::Ctr(_, els) | Pattern::Tup(els) | Pattern::Lst(els) => { - ChildrenIter::Many(Box::new(els.iter_mut())) - } - Pattern::Var(_) | Pattern::Num(_) | Pattern::Str(_) => ChildrenIter::zero(), + Pattern::Ctr(_, els) | Pattern::Tup(els) | Pattern::Lst(els) => ChildrenIter::Vec(els.iter_mut()), + Pattern::Var(_) | Pattern::Num(_) | Pattern::Str(_) => ChildrenIter::Zero([].into_iter()), } } @@ -861,8 +889,8 @@ impl Pattern { let mut to_visit = vec![self]; let mut els = vec![]; while let Some(pat) = to_visit.pop() { - to_visit.extend(pat.children().rev()); els.push(pat); + to_visit.extend(pat.children().rev()); } els.into_iter() } diff --git a/src/term/parser/parser.rs b/src/term/parser/parser.rs index f48f1c06f..48ba27bb3 100644 --- a/src/term/parser/parser.rs +++ b/src/term/parser/parser.rs @@ -298,7 +298,7 @@ where } } let mat = Term::Mat { args: args_no_bind, rules }; - binds.into_iter().rev().fold(mat, |acc, (bind, arg)| Term::Let { + binds.into_iter().rfold(mat, |acc, (bind, arg)| Term::Let { pat: Pattern::Var(Some(bind)), val: Box::new(arg), nxt: Box::new(acc), diff --git a/src/term/transform/desugar_implicit_match_binds.rs b/src/term/transform/desugar_implicit_match_binds.rs index 5aa9a70dc..079c8c13f 100644 --- a/src/term/transform/desugar_implicit_match_binds.rs +++ b/src/term/transform/desugar_implicit_match_binds.rs @@ -1,6 +1,29 @@ use crate::term::{Adts, Book, Constructors, Name, NumCtr, Pattern, Term}; impl Book { + /// Converts implicit match binds into explicit ones, using the + /// field names specified in the ADT declaration or the default + /// names for builtin constructors. + /// + /// Example: + /// ```hvm + /// data MyList = (Cons h t) | Nil + /// match x y { + /// 0 Nil: (A) + /// 0 Cons: (B y.h y.t) + /// 1+ Nil: (C x-1) + /// 1+p (Cons x xs): (D p x xs) + /// } + /// ``` + /// becomes + /// ```hvm + /// match x y { + /// 0 Nil: (A) + /// 0 (Cons y.h y.t): (B y.h y.t) + /// 1+x-1 Nil: (C x-1) + /// 1+p (Cons x xs): (D p x xs) + /// } + /// ``` pub fn desugar_implicit_match_binds(&mut self) { for def in self.defs.values_mut() { for rule in &mut def.rules { @@ -16,6 +39,7 @@ impl Term { for child in self.children_mut() { child.desugar_implicit_match_binds(ctrs, adts); } + if let Term::Mat { args, rules } = self { // Make all the matched terms variables let mut match_args = vec![]; @@ -59,7 +83,7 @@ impl Term { } // Add the binds to the extracted term vars. - *self = match_args.into_iter().rev().fold(std::mem::take(self), |nxt, (nam, val)| { + *self = match_args.into_iter().rfold(std::mem::take(self), |nxt, (nam, val)| { if let Some(val) = val { // Non-Var term that was extracted. Term::Let { pat: Pattern::Var(Some(nam)), val: Box::new(val), nxt: Box::new(nxt) } diff --git a/src/term/transform/encode_adts.rs b/src/term/transform/encode_adts.rs index fa2c5b98f..a4a51f406 100644 --- a/src/term/transform/encode_adts.rs +++ b/src/term/transform/encode_adts.rs @@ -30,21 +30,19 @@ fn encode_ctr( AdtEncoding::Scott => { let ctr = Term::Var { nam: ctr_name.clone() }; let app = ctr_args.iter().cloned().fold(ctr, Term::arg_call); - let lam = ctrs.into_iter().rev().fold(app, |acc, arg| Term::named_lam(arg.clone(), acc)); - ctr_args.into_iter().rev().fold(lam, |acc, arg| Term::named_lam(arg, acc)) + let lam = ctrs.into_iter().rfold(app, |acc, arg| Term::named_lam(arg, acc)); + ctr_args.into_iter().rfold(lam, |acc, arg| Term::named_lam(arg, acc)) } // λarg1 λarg2 #type λctr1 #type λctr2 #type.ctr2.arg2(#type.ctr2.arg1(ctr2 arg1) arg2) AdtEncoding::TaggedScott => { let ctr = Term::Var { nam: ctr_name.clone() }; - let app = ctr_args.iter().cloned().fold(ctr, |acc, nam| { - let tag = Tag::adt_name(adt_name); - Term::tagged_app(tag, acc, Term::Var { nam }) - }); - let lam = ctrs - .into_iter() - .rev() - .fold(app, |acc, arg| Term::tagged_lam(Tag::adt_name(adt_name), arg.clone(), acc)); - ctr_args.into_iter().rev().fold(lam, |acc, arg| Term::named_lam(arg, acc)) + let app = ctr_args + .iter() + .cloned() + .fold(ctr, |acc, nam| Term::tagged_app(Tag::adt_name(adt_name), acc, Term::Var { nam })); + let lam = + ctrs.into_iter().rfold(app, |acc, arg| Term::tagged_lam(Tag::adt_name(adt_name), Some(arg), acc)); + ctr_args.into_iter().rfold(lam, |acc, arg| Term::named_lam(arg, acc)) } } } diff --git a/src/term/transform/encode_pattern_matching.rs b/src/term/transform/encode_pattern_matching.rs index 978e31168..32123d11f 100644 --- a/src/term/transform/encode_pattern_matching.rs +++ b/src/term/transform/encode_pattern_matching.rs @@ -11,7 +11,16 @@ use crate::{ }; impl Book { - /// Encodes pattern matching expressions in the book functions according to the adt_encoding. + /// Encodes simple pattern matching expressions in the book into + /// their native/core form. + /// See [`super::simplify_matches::simplify_match_expression`] for + /// the meaning of "simple" used here. + /// + /// ADT matches are encoded based on `adt_encoding`. + /// + /// Num matches are encoded as a sequence of native num matches (on 0 and 1+). + /// + /// Var and pair matches become a let expression. pub fn encode_simple_matches(&mut self, adt_encoding: AdtEncoding) { for def in self.defs.values_mut() { for rule in &mut def.rules { @@ -72,7 +81,7 @@ fn encode_num_succ(arg: Term, mut rules: Vec) -> Term { }; let last_arm = Term::lam(last_var, last_rule.body); - rules.into_iter().rev().fold(last_arm, |term, rule| { + rules.into_iter().rfold(last_arm, |term, rule| { let rules = vec![Rule { pats: vec![Pattern::Num(NumCtr::Num(0))], body: rule.body }, Rule { pats: vec![Pattern::Num(NumCtr::Succ(1, None))], body: term, @@ -152,8 +161,7 @@ fn encode_adt(arg: Term, rules: Vec, adt: Name, adt_encoding: AdtEncoding) AdtEncoding::Scott => { let mut arms = vec![]; for rule in rules { - let body = rule.body; - let body = rule.pats[0].named_binds().rev().fold(body, |bod, nam| Term::named_lam(nam.clone(), bod)); + let body = rule.pats[0].binds().cloned().rfold(rule.body, |bod, nam| Term::lam(nam, bod)); arms.push(body); } Term::call(arg, arms) @@ -163,9 +171,9 @@ fn encode_adt(arg: Term, rules: Vec, adt: Name, adt_encoding: AdtEncoding) let mut arms = vec![]; for rule in rules.into_iter() { let body = rule.pats[0] - .named_binds() - .rev() - .fold(rule.body, |bod, var| Term::tagged_lam(Tag::adt_name(&adt), var.clone(), bod)); + .binds() + .cloned() + .rfold(rule.body, |bod, nam| Term::tagged_lam(Tag::adt_name(&adt), nam, bod)); arms.push(body); } Term::tagged_call(Tag::adt_name(&adt), arg, arms) diff --git a/src/term/transform/linearize_matches.rs b/src/term/transform/linearize_matches.rs index d359c43b3..a2d280b0a 100644 --- a/src/term/transform/linearize_matches.rs +++ b/src/term/transform/linearize_matches.rs @@ -53,7 +53,7 @@ pub fn lift_match_vars(match_term: &mut Term, lift_all_vars: bool) -> &mut Term .body .free_vars() .into_iter() - .filter(|(name, _)| !rule.pats.iter().any(|p| p.named_binds().contains(name))) + .filter(|(name, _)| !rule.pats.iter().any(|p| p.binds().flatten().contains(name))) }); // Collect the vars. @@ -75,7 +75,7 @@ pub fn lift_match_vars(match_term: &mut Term, lift_all_vars: bool) -> &mut Term // Add lambdas to the arms for rule in rules { let old_body = std::mem::take(&mut rule.body); - rule.body = free_vars.iter().rev().fold(old_body, |body, var| Term::named_lam(var.clone(), body)); + rule.body = free_vars.iter().cloned().rfold(old_body, |body, nam| Term::named_lam(nam, body)); } // Add apps to the match diff --git a/src/term/transform/resolve_refs.rs b/src/term/transform/resolve_refs.rs index 311cde6d6..d1527f5a2 100644 --- a/src/term/transform/resolve_refs.rs +++ b/src/term/transform/resolve_refs.rs @@ -34,8 +34,8 @@ impl Ctx<'_> { for rule in def.rules.iter_mut() { let mut scope = HashMap::new(); - for name in rule.pats.iter().flat_map(Pattern::named_binds) { - push_scope(Some(name), &mut scope); + for name in rule.pats.iter().flat_map(Pattern::binds) { + push_scope(name.as_ref(), &mut scope); } let res = rule.body.resolve_refs(&def_names, self.book.entrypoint.as_ref(), &mut scope); @@ -72,12 +72,11 @@ impl Term { } for (child, binds) in self.children_mut_with_binds() { - let binds: Vec<_> = binds.collect(); - for bind in binds.iter() { + for bind in binds.clone() { push_scope(bind.as_ref(), scope); } child.resolve_refs(def_names, main, scope)?; - for bind in binds.iter() { + for bind in binds.rev() { pop_scope(bind.as_ref(), scope); } } diff --git a/src/term/transform/simplify_matches.rs b/src/term/transform/simplify_matches.rs index 7fa4c3243..1201cbab6 100644 --- a/src/term/transform/simplify_matches.rs +++ b/src/term/transform/simplify_matches.rs @@ -378,7 +378,7 @@ fn extract_args(args: &mut [Term]) -> Vec<(Name, Term)> { /// /// `vec![(%match_arg0, arg)]` + `term` => `let %match_arg0 = arg; term` fn bind_extracted_args(extracted: Vec<(Name, Term)>, term: Term) -> Term { - extracted.into_iter().rev().fold(term, |term, (nam, val)| Term::Let { + extracted.into_iter().rfold(term, |term, (nam, val)| Term::Let { pat: Pattern::Var(Some(nam)), val: Box::new(val), nxt: Box::new(term), diff --git a/src/term/util.rs b/src/term/util.rs deleted file mode 100644 index 52b8aed75..000000000 --- a/src/term/util.rs +++ /dev/null @@ -1,56 +0,0 @@ -// TODO: Find a way to implement Clone for ChildrenIter - -/// Iterator for tree children -pub enum ChildrenIter<'a, T: 'a> { - Zero(std::array::IntoIter), - One(std::array::IntoIter), - Two(std::array::IntoIter), - Many(Box + 'a>), -} - -impl<'a, T: 'a> ChildrenIter<'a, T> { - pub fn zero() -> Self { - ChildrenIter::Zero([].into_iter()) - } - - pub fn one(value: T) -> Self { - ChildrenIter::One([value].into_iter()) - } - - pub fn two(fst: T, snd: T) -> Self { - ChildrenIter::Two([fst, snd].into_iter()) - } -} - -impl<'a, T: 'a> Iterator for ChildrenIter<'a, T> { - type Item = T; - - fn next(&mut self) -> Option { - match self { - ChildrenIter::Zero(it) => it.next(), - ChildrenIter::One(it) => it.next(), - ChildrenIter::Two(it) => it.next(), - ChildrenIter::Many(it) => it.next(), - } - } - - fn size_hint(&self) -> (usize, Option) { - match self { - ChildrenIter::Zero(it) => it.size_hint(), - ChildrenIter::One(it) => it.size_hint(), - ChildrenIter::Two(it) => it.size_hint(), - ChildrenIter::Many(it) => it.size_hint(), - } - } -} - -impl<'a, T: 'a> DoubleEndedIterator for ChildrenIter<'a, T> { - fn next_back(&mut self) -> Option { - match self { - ChildrenIter::Zero(it) => it.next_back(), - ChildrenIter::One(it) => it.next_back(), - ChildrenIter::Two(it) => it.next_back(), - ChildrenIter::Many(it) => it.next_back(), - } - } -}