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#[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
28pub type BuiltinFunction = fn(Vec<Gc<Value<Context>>>) -> Result<Gc<Value<Context>>, RuntimeError>;
30
31pub type UserFunction = (Gc<Expr>, GcLinkedList<(Symbol, Gc<Value<Context>>)>);
33
34#[derive(Clone, Debug, Finalize, PartialEq, Trace)]
36pub enum Expr {
37 Call(Gc<Prim>, Vec<Gc<Prim>>),
39
40 If(Gc<Prim>, Gc<Expr>, Gc<Expr>),
42
43 Let(Option<Symbol>, Gc<Expr>, Gc<Expr>),
45
46 Prim(Gc<Prim>),
48}
49
50impl Expr {
51 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#[derive(Clone, Debug, Finalize, PartialEq, Trace)]
100pub enum Prim {
101 Fn(Option<Symbol>, Gc<Args<Context>>, Gc<Expr>),
103
104 Lit(Gc<Value<Context>>),
106
107 Var(Symbol),
109
110 Vec(Vec<Gc<Prim>>),
112}
113
114impl Prim {
115 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}