oftlisp/ast/
mod.rs

1//! The basic AST types.
2
3mod args;
4mod expr;
5mod header;
6
7use std::fmt::{Debug, Formatter, Result as FmtResult};
8
9use gc::Gc;
10
11pub use ast::args::{Args, ArgsBindingError, ArgsConvertError};
12pub use ast::expr::Expr;
13pub use ast::header::{ModuleHeaderError, parse_module_header};
14use context::Context;
15use symbol::Symbol;
16use util::{as_list, as_shl};
17use value::Value;
18
19/// An error converting a value to an AST node.
20pub enum ConvertError<C: 'static + Context> {
21    /// An error parsing the arguments of a `defn` or `fn`.
22    ArgsConvertError(ArgsConvertError<C>),
23
24    /// A builtin was used in an invalid way.
25    InvalidBuiltin(&'static str, Gc<Value<C>>),
26
27    /// An invalid value was found in a position where a decl should have
28    /// appeared.
29    InvalidDecl(Gc<Value<C>>),
30
31    /// A `def` decl was invalid.
32    InvalidDef(Gc<Value<C>>),
33
34    /// A `defn` decl was invalid.
35    InvalidDefn(Gc<Value<C>>),
36
37    /// A value of an invalid type was encountered where an expr was expected.
38    InvalidExpr(Gc<Value<C>>),
39}
40
41impl<C: 'static + Context> Debug for ConvertError<C> {
42    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
43        match *self {
44            ConvertError::ArgsConvertError(ref err) => {
45                fmt.debug_tuple("ArgsConvertError").field(err).finish()
46            }
47            ConvertError::InvalidBuiltin(ref name, ref val) => {
48                fmt.debug_tuple("InvalidBuiltin")
49                    .field(name)
50                    .field(val)
51                    .finish()
52            }
53            ConvertError::InvalidDecl(ref val) => {
54                fmt.debug_tuple("InvalidDecl").field(val).finish()
55            }
56            ConvertError::InvalidDef(ref val) => fmt.debug_tuple("InvalidDef").field(val).finish(),
57            ConvertError::InvalidDefn(ref val) => {
58                fmt.debug_tuple("InvalidDefn").field(val).finish()
59            }
60            ConvertError::InvalidExpr(ref val) => {
61                fmt.debug_tuple("InvalidExpr").field(val).finish()
62            }
63        }
64    }
65}
66
67impl<C: 'static + Context> From<ArgsConvertError<C>> for ConvertError<C> {
68    fn from(err: ArgsConvertError<C>) -> ConvertError<C> {
69        ConvertError::ArgsConvertError(err)
70    }
71}
72
73/// Converts the body values of a module to an AST.
74pub fn convert_body<C: 'static + Context>(
75    body: Vec<Gc<Value<C>>>,
76) -> Result<Vec<(Symbol, Gc<Expr<C>>)>, ConvertError<C>> {
77    body.into_iter().map(convert_decl).collect()
78}
79
80/// Converts a declaration to its AST node.
81pub fn convert_decl<C: 'static + Context>(
82    value: Gc<Value<C>>,
83) -> Result<(Symbol, Gc<Expr<C>>), ConvertError<C>> {
84    let (head, mut rest) = as_shl(value.clone()).ok_or_else(|| {
85        ConvertError::InvalidDecl(value.clone())
86    })?;
87    match head.as_str() {
88        "def" => {
89            if rest.len() == 2 {
90                let value = rest.pop().unwrap();
91                let name = rest.pop().unwrap();
92                assert_eq!(rest.len(), 0);
93                if let Value::Symbol(name, _) = *name {
94                    convert_expr(value).map(|expr| (name, expr))
95                } else {
96                    Err(ConvertError::InvalidDef(value))
97                }
98            } else {
99                Err(ConvertError::InvalidDef(value))
100            }
101        }
102        "defn" => {
103            if rest.len() > 2 {
104                let name = if let Value::Symbol(sym, _) = *rest.remove(0) {
105                    sym
106                } else {
107                    return Err(ConvertError::InvalidDefn(value));
108                };
109                let args = rest.remove(0);
110                let expr = convert_fn(Some(name), args, rest)?;
111                Ok((name, expr))
112            } else {
113                Err(ConvertError::InvalidDefn(value))
114            }
115        }
116        _ => Err(ConvertError::InvalidDecl(value)),
117    }
118}
119
120/// Converts an expression to its AST node.
121pub fn convert_expr<C: 'static + Context>(
122    value: Gc<Value<C>>,
123) -> Result<Gc<Expr<C>>, ConvertError<C>> {
124    match *value.clone() {
125        Value::Cons(..) => {
126            if let Some(mut l) = as_list(value.clone()) {
127                let func = l.remove(0);
128                match *func {
129                    Value::Symbol(s, _) if s.as_str() == "def" || s.as_str() == "defn" => {
130                        let (n, e) = convert_decl(value)?;
131                        Ok(Gc::new(Expr::Def(n, e)))
132                    }
133                    Value::Symbol(s, _) if s.as_str() == "fn" => {
134                        if l.len() > 1 {
135                            let args = l.remove(0);
136                            convert_fn(None, args, l)
137                        } else {
138                            unimplemented!("invalid lambda: {:?}", l);
139                        }
140                    }
141                    Value::Symbol(s, _) if s.as_str() == "if" => {
142                        if l.len() == 2 {
143                            let t = convert_expr(l.pop().unwrap())?;
144                            let c = convert_expr(l.pop().unwrap())?;
145                            let nil = Gc::new(Value::Nil(Default::default()));
146                            let nil = Gc::new(Expr::Literal(nil));
147                            Ok(Gc::new(Expr::If(c, t, nil)))
148                        } else if l.len() == 3 {
149                            let e = convert_expr(l.pop().unwrap())?;
150                            let t = convert_expr(l.pop().unwrap())?;
151                            let c = convert_expr(l.pop().unwrap())?;
152                            Ok(Gc::new(Expr::If(c, t, e)))
153                        } else {
154                            Err(ConvertError::InvalidBuiltin("if".into(), value))
155                        }
156                    }
157                    Value::Symbol(s, _) if s.as_str() == "macro-progn" || s.as_str() == "progn" => {
158                        let exprs = l.into_iter().map(convert_expr).collect::<Result<_, _>>()?;
159                        Ok(Gc::new(Expr::Progn(exprs)))
160                    }
161                    Value::Symbol(s, _) if s.as_str() == "quote" => {
162                        if l.len() == 1 {
163                            let value = l.pop().unwrap();
164                            Ok(Gc::new(Expr::Literal(value)))
165                        } else {
166                            Err(ConvertError::InvalidBuiltin("quote".into(), value))
167                        }
168                    }
169                    _ => {
170                        let args = l.into_iter()
171                            .map(convert_expr)
172                            .collect::<Result<Vec<_>, _>>()?;
173                        convert_expr(func).map(|func| Gc::new(Expr::Call(func, args)))
174                    }
175                }
176            } else {
177                Err(ConvertError::InvalidExpr(value))
178            }
179        }
180        Value::Bytes(..) |
181        Value::Fixnum(..) |
182        Value::String(..) => Ok(Gc::new(Expr::Literal(value))),
183        Value::Symbol(sym, _) => Ok(Gc::new(Expr::Variable(sym))),
184        Value::Vector(ref v, _) => {
185            let v = v.iter()
186                .cloned()
187                .map(|v| convert_expr(v))
188                .collect::<Result<_, _>>()?;
189            Ok(Gc::new(Expr::Vector(v)))
190        }
191        _ => Err(ConvertError::InvalidExpr(value)),
192    }
193}
194
195pub(crate) fn convert_fn<C: 'static + Context>(
196    name: Option<Symbol>,
197    args: Gc<Value<C>>,
198    body: Vec<Gc<Value<C>>>,
199) -> Result<Gc<Expr<C>>, ConvertError<C>> {
200    let mut body = body.into_iter()
201        .map(convert_expr)
202        .collect::<Result<Vec<_>, _>>()?;
203    let tail = body.pop().unwrap();
204    let args = Args::from_value(args)?;
205    Ok(Gc::new(Expr::Lambda(name, Gc::new(args), body, tail)))
206}