///|
pub enum Pattern {
  Wild
  Var(String)
  VarIf(String, (Id) -> Bool)
  Sym(String)
  Num(Float)
  Node(String, Array[Pattern])
}

///|
pub fn pat_wild() -> Pattern {
  Pattern::Wild
}

///|
pub fn pat_var(name : String) -> Pattern {
  Pattern::Var(name)
}

///|
pub fn pat_var_if(name : String, pred : (Id) -> Bool) -> Pattern {
  Pattern::VarIf(name, pred)
}

///|
pub fn pat_sym(name : String) -> Pattern {
  Pattern::Sym(name)
}

///|
pub fn pat_num(n : Float) -> Pattern {
  Pattern::Num(n)
}

///|
pub fn pat_node(op : String, children : Array[Pattern]) -> Pattern {
  Pattern::Node(op, children)
}

///|
pub fn parse_pattern(expr : Expr) -> Pattern raise {
  match expr {
    Expr::Leaf(name) =>
      if name.has_prefix("?") {
        let v_view = try! name[1:]
        Pattern::Var(v_view.to_string())
      } else {
        match parse_number_literal(name) {
          Some(n) => Pattern::Num(n)
          None => Pattern::Sym(name)
        }
      }
    Expr::Node(op, children) => {
      let pats = children.map(child => parse_pattern(child))
      Pattern::Node(op, pats)
    }
  }
}