oftlisp_anf/
types.rs

1use std::collections::{BTreeSet, HashMap};
2use std::fmt::{Display, Formatter, Result as FmtResult, Write};
3
4use gc::Gc;
5use itertools::Itertools;
6use oftlisp::{Context as OftLispContext, Symbol, Value};
7use oftlisp::ast::{Args, Expr as AstExpr};
8use oftlisp::collections::GcLinkedList;
9
10use errors::RuntimeError;
11
12/// The `Context` provided by this crate.
13#[derive(Clone, Debug, Finalize, Trace)]
14pub struct Context;
15
16impl OftLispContext for Context {
17    type BuiltinFunction = BuiltinFunction;
18    type Expr = Expr;
19    type ObjectVtable = HashMap<Symbol, Gc<Value<Context>>>;
20    type UserFunction = UserFunction;
21    type ValueMeta = ();
22
23    fn from_expr(expr: Gc<AstExpr<Self>>) -> Gc<Expr> {
24        Self::convert_expr(expr)
25    }
26}
27
28/// The type of a built-in function.
29pub type BuiltinFunction = fn(Vec<Gc<Value<Context>>>) -> Result<Gc<Value<Context>>, RuntimeError>;
30
31/// The type of a user-defined function.
32pub type UserFunction = (Gc<Expr>, GcLinkedList<(Symbol, Gc<Value<Context>>)>);
33
34/// A complex expression, i.e. one that can fail to normalize.
35#[derive(Clone, Debug, Finalize, PartialEq, Trace)]
36pub enum Expr {
37    /// A function call.
38    Call(Gc<Prim>, Vec<Gc<Prim>>),
39
40    /// A conditional expression.
41    If(Gc<Prim>, Gc<Expr>, Gc<Expr>),
42
43    /// A let binding.
44    Let(Option<Symbol>, Gc<Expr>, Gc<Expr>),
45
46    /// A primitive expression.
47    Prim(Gc<Prim>),
48}
49
50impl Expr {
51    /// Returns the free variables of the expression.
52    pub fn freevars(&self) -> BTreeSet<Symbol> {
53        match *self {
54            Expr::Call(ref f, ref a) => {
55                let mut fv = f.freevars();
56                for a in a {
57                    fv.extend(a.freevars());
58                }
59                fv
60            },
61            Expr::If(ref c, ref t, ref e) => {
62                let mut fv = c.freevars();
63                fv.extend(&t.freevars());
64                fv.extend(&e.freevars());
65                fv
66            },
67            Expr::Let(n, ref a, ref b) => {
68                let mut fv = b.freevars();
69                if let Some(n) = n {
70                    fv.remove(&n);
71                }
72                fv.extend(&a.freevars());
73                fv
74            },
75            Expr::Prim(ref p) => p.freevars(),
76        }
77    }
78}
79
80impl Display for Expr {
81    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
82        match *self {
83            Expr::Call(ref f, ref a) => {
84                write!(fmt, "{}({})", f, a.iter().join(" "))
85            },
86            Expr::If(ref c, ref t, ref e) => {
87                write!(fmt, "if({}) {{ {} }} else {{ {} }}", c, t, e)
88            },
89            Expr::Let(None, ref x, ref y) => write!(fmt, "({}) >> ({})", x, y),
90            Expr::Let(Some(n), ref x, ref y) => {
91                write!(fmt, "let {} = ({}) in {}", n, x, y)
92            },
93            Expr::Prim(ref p) => Display::fmt(p, fmt),
94        }
95    }
96}
97
98/// A primitive expression, i.e. one that immediately normalizes.
99#[derive(Clone, Debug, Finalize, PartialEq, Trace)]
100pub enum Prim {
101    /// A function literal, i.e. a lambda.
102    Fn(Option<Symbol>, Gc<Args<Context>>, Gc<Expr>),
103
104    /// A literal value.
105    Lit(Gc<Value<Context>>),
106
107    /// A variable.
108    Var(Symbol),
109
110    /// A literal vector.
111    Vec(Vec<Gc<Prim>>),
112}
113
114impl Prim {
115    /// Returns the free variables of the expression.
116    pub fn freevars(&self) -> BTreeSet<Symbol> {
117        match *self {
118            Prim::Fn(n, ref a, ref b) => {
119                let mut fv = b.freevars();
120                for n in &a.required {
121                    fv.remove(n);
122                }
123                for &(ref n, _) in &a.optional {
124                    fv.remove(n);
125                }
126                if let Some(n) = a.rest {
127                    fv.remove(&n);
128                }
129                if let Some(n) = n {
130                    fv.remove(&n);
131                }
132                fv
133            },
134            Prim::Lit(_) => BTreeSet::new(),
135            Prim::Var(s) => {
136                let mut fv = BTreeSet::new();
137                fv.insert(s);
138                fv
139            },
140            Prim::Vec(ref v) => {
141                let mut fv = BTreeSet::new();
142                for v in v {
143                    fv.extend(&v.freevars());
144                }
145                fv
146            },
147        }
148    }
149}
150
151impl Display for Prim {
152    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
153        match *self {
154            Prim::Fn(n, ref a, ref b) => {
155                fmt.write_str("fn")?;
156                if let Some(n) = n {
157                    fmt.write_char(' ')?;
158                    Display::fmt(&n, fmt)?;
159                }
160                Display::fmt(a, fmt)?;
161                fmt.write_str(" -> ")?;
162                Display::fmt(b, fmt)
163            },
164            Prim::Lit(ref v) => Display::fmt(v, fmt),
165            Prim::Var(ref n) => Display::fmt(n, fmt),
166            Prim::Vec(ref v) => {
167                fmt.write_char('[')?;
168                fmt.write_str(&v.iter().join(" "))?;
169                fmt.write_char(']')
170            },
171        }
172    }
173}