oftlisp/ast/
header.rs

1use std::collections::HashMap;
2
3use gc::Gc;
4
5use context::Context;
6use symbol::Symbol;
7use util::{as_sym_list, is_shl};
8use value::Value;
9
10/// An error occurring from a call to
11/// [`parse_module_header`](fn.parse_module_header.html).
12#[derive(Clone, Debug, Eq, Finalize, Hash, PartialEq, Trace)]
13pub enum ModuleHeaderError {
14    /// An `import` form was invalid.
15    BadImportForm,
16
17    /// The `module` form was invalid.
18    BadModuleForm,
19
20    /// No `module` form was present.
21    NoModuleForm,
22}
23
24/// Parses out the `module` and `import` forms from the given values, returning the body.
25pub fn parse_module_header<C: 'static + Context>(
26    mut values: Vec<Gc<Value<C>>>,
27) -> Result<(Symbol, Vec<Symbol>, HashMap<Symbol, Vec<Symbol>>, Vec<Gc<Value<C>>>), ModuleHeaderError> {
28    fn parse_header_form<C: 'static + Context>(
29        import: bool,
30        value: Gc<Value<C>>,
31    ) -> Result<(Symbol, Vec<Symbol>), ModuleHeaderError> {
32        if let Some(mut sym_list) = as_sym_list(value) {
33            if sym_list.len() >= 2 {
34                let head = sym_list.remove(0);
35                if import && head != Symbol::from("import") {
36                    Err(ModuleHeaderError::BadImportForm)
37                } else if !import && head != Symbol::from("module") {
38                    Err(ModuleHeaderError::BadModuleForm)
39                } else {
40                    let name = sym_list.remove(0);
41                    Ok((name, sym_list))
42                }
43            } else {
44                Err(if import {
45                    ModuleHeaderError::BadImportForm
46                } else {
47                    ModuleHeaderError::BadModuleForm
48                })
49            }
50        } else {
51            Err(if import {
52                ModuleHeaderError::BadImportForm
53            } else {
54                ModuleHeaderError::BadModuleForm
55            })
56        }
57    }
58
59    if values.len() == 0 {
60        return Err(ModuleHeaderError::NoModuleForm);
61    }
62
63    let import_sym = Symbol::from("import");
64    let (name, exports) = parse_header_form(false, values.remove(0))?;
65    let end = values
66        .iter()
67        .cloned()
68        .position(|x| !is_shl(import_sym, x))
69        .unwrap_or_else(|| values.len());
70
71    let imports = values
72        .drain(..end)
73        .map(|v| parse_header_form(true, v))
74        .collect::<Result<_, _>>()?;
75    Ok((name, exports, imports, values))
76}