///|
pub fn visit_design(design : Design, visit : (String) -> Unit) -> Unit {
  for mod in design.modules {
    visit(mod.name)
    for item in mod.items {
      visit_item(item, visit)
    }
  }
}

///|
fn visit_item(item : ModuleItem, visit : (String) -> Unit) -> Unit {
  match item {
    Assign(assign) => {
      visit_expression(assign.target, visit)
      visit_expression(assign.value, visit)
    }
    Always(always) => visit_statement(always.body, visit)
    Instance(instance) =>
      for connection in instance.connections {
        visit_expression(connection.expression, visit)
      }
    Statement(statement) => visit_statement(statement, visit)
    Unknown(_) => ()
  }
}

///|
fn visit_statement(statement : Statement, visit : (String) -> Unit) -> Unit {
  match statement {
    Empty(_) | Unknown(_) => ()
    Block(statements, _) =>
      for statement in statements {
        visit_statement(statement, visit)
      }
    Assignment(target, value, _, _) => {
      visit_expression(target, visit)
      visit_expression(value, visit)
    }
    If(condition, then_branch, else_branch, _) => {
      visit_expression(condition, visit)
      visit_statement(then_branch, visit)
      match else_branch {
        Some(statement) => visit_statement(statement, visit)
        None => ()
      }
    }
    Case(expression, arms, _) => {
      visit_expression(expression, visit)
      for arm in arms {
        for choice in arm.choices {
          visit_expression(choice, visit)
        }
        visit_statement(arm.body, visit)
      }
    }
  }
}

///|
fn visit_expression(expression : Expression, visit : (String) -> Unit) -> Unit {
  match expression {
    Name(name, _) => visit(name)
    Number(_, _) | StringLiteral(_, _) | Unknown(_) => ()
    Unary(_, inner, _) => visit_expression(inner, visit)
    Binary(left, _, right, _) => {
      visit_expression(left, visit)
      visit_expression(right, visit)
    }
    Index(base, index, _) => {
      visit_expression(base, visit)
      visit_expression(index, visit)
    }
  }
}