summaryrefslogtreecommitdiff
path: root/dhall/src/imports.rs
blob: ea3ef011801efd8b44235c6e27ce20b03921ba91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// use dhall_core::{Expr, FilePrefix, Import, ImportLocation, ImportMode, X};
use dhall_core::{Expr, Import, StringLike, X};
// use std::path::Path;
use dhall_core::*;
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;

pub fn panic_imports<Label: StringLike, S: Clone>(
    expr: &Expr<Label, S, Import>,
) -> Expr<Label, S, X> {
    let no_import = |i: &Import| -> X { panic!("ahhh import: {:?}", i) };
    expr.map_embed(&no_import)
}

/// A root from which to resolve relative imports.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ImportRoot {
    LocalDir(PathBuf),
}

fn resolve_import(
    import: &Import,
    root: &ImportRoot,
) -> Result<Expr<String, X, X>, DhallError> {
    use self::ImportRoot::*;
    use dhall_core::FilePrefix::*;
    use dhall_core::ImportLocation::*;
    let cwd = match root {
        LocalDir(cwd) => cwd,
    };
    match &import.location {
        Local(prefix, path) => {
            let path = match prefix {
                Parent => cwd.parent().unwrap().join(path),
                _ => unimplemented!("{:?}", import),
            };
            load_dhall_file(&path, true)
        }
    }
}

#[derive(Debug)]
pub enum DhallError {
    ParseError(parser::ParseError),
    IOError(std::io::Error),
}
impl From<parser::ParseError> for DhallError {
    fn from(e: parser::ParseError) -> Self {
        DhallError::ParseError(e)
    }
}
impl From<std::io::Error> for DhallError {
    fn from(e: std::io::Error) -> Self {
        DhallError::IOError(e)
    }
}
impl fmt::Display for DhallError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::DhallError::*;
        match self {
            ParseError(e) => e.fmt(f),
            IOError(e) => e.fmt(f),
        }
    }
}

pub fn load_dhall_file(
    f: &Path,
    resolve_imports: bool,
) -> Result<Expr<String, X, X>, DhallError> {
    let mut buffer = String::new();
    File::open(f)?.read_to_string(&mut buffer)?;
    let expr = parser::parse_expr(&*buffer)?;
    let expr = expr.take_ownership_of_labels();
    let expr = if resolve_imports {
        let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned());
        let resolve = |import: &Import| -> Expr<String, X, X> {
            resolve_import(import, &root).unwrap()
        };
        let expr = expr.map_embed(&resolve).squash_embed();
        expr
    } else {
        panic_imports(&expr)
    };
    Ok(expr)
}