mod convert;
mod display;
mod print;
use std::collections::{BTreeMap, BTreeSet};
use symbol::Symbol;
pub use ast::print::PrintStyle;
#[derive(Clone, Debug, PartialEq)]
pub struct Decl<Aux> {
pub name: Symbol,
pub args: Vec<Pattern<Aux>>,
pub body: Expr<Aux>,
pub aux: Aux,
}
impl<Aux> Decl<Aux> {
pub fn aux_ref(&self) -> &Aux {
&self.aux
}
pub fn freevars(&self) -> BTreeSet<Symbol> {
let mut vars = self.body.freevars();
for arg in &self.args {
for var in arg.freevars() {
vars.remove(&var);
}
}
vars.remove(&self.name);
vars
}
pub fn map_aux<Aux2, F: Copy + Fn(Aux) -> Aux2>(self, f: F) -> Decl<Aux2> {
Decl {
name: self.name,
args: self.args.into_iter().map(|arg| arg.map_aux(f)).collect(),
body: self.body.map_aux(f),
aux: f(self.aux),
}
}
}
impl<Aux: Clone> Decl<Aux> {
pub fn aux(&self) -> Aux {
self.aux_ref().clone()
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Pattern<Aux> {
Binding(Symbol, Aux),
Cons(Box<Pattern<Aux>>, Box<Pattern<Aux>>, Aux),
Literal(Literal, Aux),
}
impl<Aux> Pattern<Aux> {
pub fn aux_ref(&self) -> &Aux {
match *self {
Pattern::Binding(_, ref aux)
| Pattern::Cons(_, _, ref aux)
| Pattern::Literal(_, ref aux) => aux,
}
}
pub fn freevars(&self) -> BTreeSet<Symbol> {
match *self {
Pattern::Binding(var, _) => {
let mut set = BTreeSet::new();
set.insert(var);
set
}
Pattern::Cons(ref l, ref r, _) => {
l.freevars().into_iter().chain(r.freevars()).collect()
}
Pattern::Literal(_, _) => BTreeSet::new(),
}
}
pub fn map_aux<Aux2, F: Copy + Fn(Aux) -> Aux2>(self, f: F) -> Pattern<Aux2> {
match self {
Pattern::Binding(var, aux) => Pattern::Binding(var, f(aux)),
Pattern::Cons(l, r, aux) => {
Pattern::Cons(Box::new(l.map_aux(f)), Box::new(r.map_aux(f)), f(aux))
}
Pattern::Literal(lit, aux) => Pattern::Literal(lit, f(aux)),
}
}
}
impl<Aux: Clone> Pattern<Aux> {
pub fn matches(&self, expr: &Expr<Aux>) -> Option<BTreeMap<Symbol, Expr<Aux>>> {
match (self, expr) {
(&Pattern::Binding(var, _), e) => {
let mut map = BTreeMap::new();
map.insert(var, e.clone());
Some(map)
}
(&Pattern::Cons(ref pl, ref pr, _), &Expr::Op(Op::Cons, ref el, ref er, _)) => {
let mut lm = pl.matches(el)?;
lm.extend(pr.matches(er)?);
Some(lm)
}
(&Pattern::Literal(l1, _), &Expr::Literal(l2, _)) if l1 == l2 => Some(BTreeMap::new()),
_ => None,
}
}
}
impl<Aux: Clone> Pattern<Aux> {
pub fn aux(&self) -> Aux {
self.aux_ref().clone()
}
}
#[derive(Clone, Debug, DisplayAttr, PartialEq)]
pub enum Expr<Aux> {
#[display(fmt = "If({}, {}, {})", _0, _1, _2)]
If(Box<Expr<Aux>>, Box<Expr<Aux>>, Box<Expr<Aux>>, Aux),
#[display(fmt = "{}", _0)]
Literal(Literal, Aux),
#[display(fmt = "{}({}, {})", _0, _1, _2)]
Op(Op, Box<Expr<Aux>>, Box<Expr<Aux>>, Aux),
#[display(fmt = "{}", _0)]
Variable(Symbol, Aux),
}
impl<Aux> Expr<Aux> {
pub fn aux_ref(&self) -> &Aux {
match *self {
Expr::If(_, _, _, ref aux)
| Expr::Literal(_, ref aux)
| Expr::Op(_, _, _, ref aux)
| Expr::Variable(_, ref aux) => aux,
}
}
pub fn free_count(&self) -> BTreeMap<Symbol, usize> {
match *self {
Expr::If(ref c, ref t, ref e, _) => {
let mut map = c.free_count();
for (var, count) in t.free_count().into_iter().chain(e.free_count()) {
*map.entry(var).or_insert(0) += count;
}
map
}
Expr::Literal(_, _) => BTreeMap::new(),
Expr::Op(_, ref l, ref r, _) => {
let mut map = l.free_count();
for (var, count) in r.free_count() {
*map.entry(var).or_insert(0) += count;
}
map
}
Expr::Variable(name, _) => {
let mut map = BTreeMap::new();
map.insert(name, 1);
map
}
}
}
pub fn freevars(&self) -> BTreeSet<Symbol> {
match *self {
Expr::If(ref c, ref t, ref e, _) => c.freevars()
.into_iter()
.chain(t.freevars())
.chain(e.freevars())
.collect(),
Expr::Literal(_, _) => BTreeSet::new(),
Expr::Op(_, ref l, ref r, _) => l.freevars().into_iter().chain(r.freevars()).collect(),
Expr::Variable(var, _) => {
let mut set = BTreeSet::new();
set.insert(var);
set
}
}
}
pub fn map_aux<Aux2, F: Copy + Fn(Aux) -> Aux2>(self, f: F) -> Expr<Aux2> {
match self {
Expr::If(c, t, e, aux) => Expr::If(
Box::new(c.map_aux(f)),
Box::new(t.map_aux(f)),
Box::new(e.map_aux(f)),
f(aux),
),
Expr::Literal(lit, aux) => Expr::Literal(lit, f(aux)),
Expr::Op(op, l, r, aux) => {
Expr::Op(op, Box::new(l.map_aux(f)), Box::new(r.map_aux(f)), f(aux))
}
Expr::Variable(var, aux) => Expr::Variable(var, f(aux)),
}
}
}
impl<Aux: Clone> Expr<Aux> {
pub fn aux(&self) -> Aux {
self.aux_ref().clone()
}
}
#[derive(Clone, Copy, Debug, DisplayAttr, PartialEq)]
#[allow(missing_docs)]
pub enum Op {
#[display(fmt = "Add")]
Add,
#[display(fmt = "App")]
App,
#[display(fmt = "Cons")]
Cons,
#[display(fmt = "Div")]
Div,
#[display(fmt = "Mod")]
Mod,
#[display(fmt = "Mul")]
Mul,
#[display(fmt = "Sub")]
Sub,
}
#[derive(Clone, Copy, Debug, DisplayAttr, PartialEq)]
pub enum Literal {
#[display(fmt = "false")]
False,
#[display(fmt = "{}", _0)]
Int(usize),
#[display(fmt = "[]")]
Nil,
#[display(fmt = "true")]
True,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Type {
Bool,
Forall(Box<Type>),
Func(Box<Type>, Box<Type>),
Int,
List(Box<Type>),
Var(usize),
}
impl Type {
pub fn argn(&self) -> usize {
match *self {
Type::Bool | Type::Int | Type::List(_) | Type::Var(_) => 0,
Type::Forall(ref ty) => ty.argn(),
Type::Func(_, ref r) => 1 + r.argn(),
}
}
}