Skip to content

Commit

Permalink
Merge pull request #221 from HigherOrderCO/chore/sc-489/simplify-hvml…
Browse files Browse the repository at this point in the history
…-passes-using-term-iterators

[sc-489] Simplify passes by using iterators over the AST
  • Loading branch information
developedby authored Mar 6, 2024
2 parents 24b6d51 + 3eff3e2 commit 093b2ea
Show file tree
Hide file tree
Showing 31 changed files with 630 additions and 1,039 deletions.
65 changes: 14 additions & 51 deletions src/term/check/ctrs_arities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,15 @@ impl Pattern {
let mut to_check = vec![self];

while let Some(pat) = to_check.pop() {
match pat {
Pattern::Ctr(name, args) => {
let expected = arities.get(name).unwrap();
let found = args.len();
if *expected != found {
return Err(MatchErr::CtrArityMismatch(name.clone(), found, *expected));
}
if let Pattern::Ctr(name, args) = pat {
let expected = arities.get(name).unwrap();
let found = args.len();
if *expected != found {
return Err(MatchErr::CtrArityMismatch(name.clone(), found, *expected));
}
Pattern::Lst(els) | Pattern::Tup(els) => {
for el in els {
to_check.push(el);
}
}
Pattern::Var(..) | Pattern::Num(..) | Pattern::Str(_) => {}
}
for child in pat.children() {
to_check.push(child);
}
}
Ok(())
Expand All @@ -71,44 +66,12 @@ impl Pattern {

impl Term {
pub fn check_ctrs_arities(&self, arities: &HashMap<Name, usize>) -> Result<(), MatchErr> {
stacker::maybe_grow(1024 * 32, 1024 * 1024, move || {
match self {
Term::Mat { args, rules } => {
for arg in args {
arg.check_ctrs_arities(arities)?;
}
for rule in rules {
for pat in &rule.pats {
pat.check_ctrs_arities(arities)?;
}
rule.body.check_ctrs_arities(arities)?;
}
}
Term::Let { pat, val, nxt } => {
pat.check_ctrs_arities(arities)?;
val.check_ctrs_arities(arities)?;
nxt.check_ctrs_arities(arities)?;
}

Term::Lst { els } | Term::Sup { els, .. } | Term::Tup { els } => {
for el in els {
el.check_ctrs_arities(arities)?;
}
}
Term::App { fun: fst, arg: snd, .. }
| Term::Dup { val: fst, nxt: snd, .. }
| Term::Opx { fst, snd, .. } => {
fst.check_ctrs_arities(arities)?;
snd.check_ctrs_arities(arities)?;
}
Term::Lam { bod, .. } | Term::Chn { bod, .. } => bod.check_ctrs_arities(arities)?,
Term::Var { .. }
| Term::Lnk { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era
| Term::Err => {}
Term::recursive_call(move || {
for pat in self.patterns() {
pat.check_ctrs_arities(arities)?;
}
for child in self.children() {
child.check_ctrs_arities(arities)?;
}
Ok(())
})
Expand Down
40 changes: 10 additions & 30 deletions src/term/check/match_arity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,39 +33,19 @@ impl Definition {

impl Term {
pub fn check_match_arity(&self) -> Result<(), MatchErr> {
stacker::maybe_grow(1024 * 32, 1024 * 1024, move || {
match self {
Term::Mat { args, rules } => {
let expected = args.len();
for rule in rules {
let found = rule.pats.len();
if found != expected {
return Err(MatchErr::ArityMismatch(found, expected));
}
rule.body.check_match_arity()?;
Term::recursive_call(move || {
if let Term::Mat { args, rules } = self {
let expected = args.len();
for rule in rules {
let found = rule.pats.len();
if found != expected {
return Err(MatchErr::ArityMismatch(found, expected));
}
}
}

Term::Lst { els } | Term::Sup { els, .. } | Term::Tup { els } => {
for el in els {
el.check_match_arity()?;
}
}
Term::App { fun: fst, arg: snd, .. }
| Term::Dup { val: fst, nxt: snd, .. }
| Term::Opx { fst, snd, .. }
| Term::Let { val: fst, nxt: snd, .. } => {
fst.check_match_arity()?;
snd.check_match_arity()?;
}
Term::Lam { bod, .. } | Term::Chn { bod, .. } => bod.check_match_arity()?,
Term::Var { .. }
| Term::Lnk { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era
| Term::Err => {}
for child in self.children() {
child.check_match_arity()?;
}
Ok(())
})
Expand Down
55 changes: 10 additions & 45 deletions src/term/check/unbound_pats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,60 +46,25 @@ impl Pattern {
let mut unbounds = HashSet::new();
let mut check = vec![self];
while let Some(pat) = check.pop() {
match pat {
Pattern::Ctr(nam, args) => {
if !is_ctr(nam) {
unbounds.insert(nam.clone());
}
check.extend(args.iter());
if let Pattern::Ctr(nam, _) = pat {
if !is_ctr(nam) {
unbounds.insert(nam.clone());
}
Pattern::Tup(args) | Pattern::Lst(args) => args.iter().for_each(|arg| check.push(arg)),
Pattern::Var(_) | Pattern::Num(_) | Pattern::Str(_) => {}
}
check.extend(pat.children());
}
unbounds
}
}

impl Term {
pub fn check_unbound_pats(&self, is_ctr: &impl Fn(&Name) -> bool) -> Result<(), UnboundCtrErr> {
stacker::maybe_grow(1024 * 32, 1024 * 1024, move || {
match self {
Term::Let { pat, val, nxt } => {
pat.check_unbounds(is_ctr)?;
val.check_unbound_pats(is_ctr)?;
nxt.check_unbound_pats(is_ctr)?;
}
Term::Mat { args, rules } => {
for arg in args {
arg.check_unbound_pats(is_ctr)?;
}
for rule in rules {
for pat in &rule.pats {
pat.check_unbounds(is_ctr)?;
}
rule.body.check_unbound_pats(is_ctr)?;
}
}
Term::Lst { els } | Term::Sup { els, .. } | Term::Tup { els } => {
for el in els {
el.check_unbound_pats(is_ctr)?;
}
}
Term::App { fun: fst, arg: snd, .. }
| Term::Dup { val: fst, nxt: snd, .. }
| Term::Opx { fst, snd, .. } => {
fst.check_unbound_pats(is_ctr)?;
snd.check_unbound_pats(is_ctr)?;
}
Term::Lam { bod, .. } | Term::Chn { bod, .. } => bod.check_unbound_pats(is_ctr)?,
Term::Var { .. }
| Term::Lnk { .. }
| Term::Ref { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Era
| Term::Err => (),
Term::recursive_call(move || {
for pat in self.patterns() {
pat.check_unbounds(is_ctr)?;
}
for child in self.children() {
child.check_unbound_pats(is_ctr)?;
}
Ok(())
})
Expand Down
67 changes: 14 additions & 53 deletions src/term/check/unbound_vars.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
diagnostics::Info,
term::{Ctx, Name, Pattern, Term},
term::{Ctx, Name, Term},
};
use std::{
collections::{hash_map::Entry, HashMap},
Expand Down Expand Up @@ -40,7 +40,7 @@ impl Ctx<'_> {
for rule in &mut def.rules {
let mut scope = HashMap::new();
for pat in &rule.pats {
pat.binds().for_each(|nam| push_scope(Some(nam), &mut scope));
pat.named_binds().for_each(|nam| push_scope(Some(nam), &mut scope));
}

rule.body.check_unbound_vars(&mut scope, &mut errs);
Expand Down Expand Up @@ -82,12 +82,7 @@ pub fn check_uses<'a>(
globals: &mut HashMap<&'a Name, (usize, usize)>,
errs: &mut Vec<UnboundVarErr>,
) {
match term {
Term::Lam { nam, bod, .. } => {
push_scope(nam.as_ref(), scope);
check_uses(bod, scope, globals, errs);
pop_scope(nam.as_ref(), scope);
}
Term::recursive_call(move || match term {
Term::Var { nam } => {
if !scope.contains_key(nam) {
errs.push(UnboundVarErr::Local(nam.clone()));
Expand All @@ -103,55 +98,21 @@ pub fn check_uses<'a>(
Term::Lnk { nam } => {
globals.entry(nam).or_default().1 += 1;
}
Term::Let { pat: Pattern::Var(nam), val, nxt } => {
check_uses(val, scope, globals, errs);
push_scope(nam.as_ref(), scope);
check_uses(nxt, scope, globals, errs);
pop_scope(nam.as_ref(), scope);
}
Term::Dup { bnd, val, nxt, .. } => {
check_uses(val, scope, globals, errs);
for bnd in bnd.iter() {
push_scope(bnd.as_ref(), scope);
}
check_uses(nxt, scope, globals, errs);
for bnd in bnd.iter() {
pop_scope(bnd.as_ref(), scope);
}
}
Term::Let { pat, val, nxt } => {
check_uses(val, scope, globals, errs);
for bnd in pat.bind_or_eras() {
push_scope(bnd.as_ref(), scope);
}
check_uses(nxt, scope, globals, errs);
for bnd in pat.bind_or_eras() {
pop_scope(bnd.as_ref(), scope);
}
}
Term::App { fun: fst, arg: snd, .. } | Term::Opx { fst, snd, .. } => {
check_uses(fst, scope, globals, errs);
check_uses(snd, scope, globals, errs);
}
Term::Mat { args, rules } => {
for arg in args {
check_uses(arg, scope, globals, errs);
}
for rule in rules {
rule.pats.iter().flat_map(|p| p.binds()).for_each(|nam| push_scope(Some(nam), scope));

check_uses(&mut rule.body, scope, globals, errs);
_ => {
for (child, binds) in term.children_mut_with_binds() {
let binds: Vec<_> = binds.collect();

rule.pats.iter().flat_map(|p| p.binds()).rev().for_each(|nam| pop_scope(Some(nam), scope));
}
}
Term::Lst { els } | Term::Sup { els, .. } | Term::Tup { els } => {
for el in els {
check_uses(el, scope, globals, errs);
for bind in binds.iter() {
push_scope(bind.as_ref(), scope);
}
check_uses(child, scope, globals, errs);
for bind in binds.iter().rev() {
pop_scope(bind.as_ref(), scope);
}
}
}
Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era | Term::Err => (),
}
})
}

fn push_scope<'a>(nam: Option<&'a Name>, scope: &mut HashMap<&'a Name, u64>) {
Expand Down
4 changes: 2 additions & 2 deletions src/term/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ macro_rules! display {

impl fmt::Display for Term {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Term::recursive_call(move || match self {
Term::Lam { tag, nam, bod } => {
write!(f, "{}λ{} {}", tag.display_padded(), var_as_str(nam), bod)
}
Expand Down Expand Up @@ -83,7 +83,7 @@ impl fmt::Display for Term {
Term::Tup { els } => write!(f, "({})", DisplayJoin(|| els.iter(), ", "),),
Term::Lst { els } => write!(f, "[{}]", DisplayJoin(|| els.iter(), ", "),),
Term::Err => write!(f, "<Invalid>"),
}
})
}
}

Expand Down
Loading

0 comments on commit 093b2ea

Please sign in to comment.