summaryrefslogtreecommitdiff
path: root/dhall/src/ctxt.rs
blob: 37fab35e285a0142a1497256f203341c0cf78376 (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use elsa::vec::FrozenVec;
use once_cell::sync::OnceCell;

use crate::semantics::{Import, ImportLocation};
use crate::syntax::Span;
use crate::Typed;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ImportId(usize);
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ImportResultId(usize);

/// What's stored for each `ImportId`. Allows getting and setting a result for this import.
pub struct StoredImport<'cx> {
    cx: Ctxt<'cx>,
    pub base_location: ImportLocation,
    pub import: Import,
    pub span: Span,
    result: OnceCell<ImportResultId>,
}

/// Implementation detail. Made public for the `Index` instances.
#[derive(Default)]
pub struct CtxtS<'cx> {
    imports: FrozenVec<Box<StoredImport<'cx>>>,
    import_results: FrozenVec<Box<Typed>>,
}

/// Context for the dhall compiler. Stores various global maps.
/// Access the relevant value using `cx[id]`.
#[derive(Copy, Clone)]
pub struct Ctxt<'cx>(&'cx CtxtS<'cx>);

impl Ctxt<'_> {
    pub fn with_new<T>(f: impl for<'cx> FnOnce(Ctxt<'cx>) -> T) -> T {
        let cx = CtxtS::default();
        let cx = Ctxt(&cx);
        f(cx)
    }
}
impl<'cx> Ctxt<'cx> {
    /// Store an import and the location relative to which it must be resolved.
    pub fn push_import(
        self,
        base_location: ImportLocation,
        import: Import,
        span: Span,
    ) -> ImportId {
        let stored = StoredImport {
            cx: self,
            base_location,
            import,
            span,
            result: OnceCell::new(),
        };
        let id = self.0.imports.len();
        self.0.imports.push(Box::new(stored));
        ImportId(id)
    }
    /// Store the result of fetching an import.
    pub fn push_import_result(self, res: Typed) -> ImportResultId {
        let id = self.0.import_results.len();
        self.0.import_results.push(Box::new(res));
        ImportResultId(id)
    }
}

impl<'cx> StoredImport<'cx> {
    /// Get the id of the result of fetching this import. Returns `None` if the result has not yet
    /// been fetched.
    pub fn get_resultid(&self) -> Option<ImportResultId> {
        self.result.get().copied()
    }
    /// Store the result of fetching this import.
    pub fn set_resultid(&self, res: ImportResultId) {
        let _ = self.result.set(res);
    }
    /// Get the result of fetching this import. Returns `None` if the result has not yet been
    /// fetched.
    pub fn get_result(&self) -> Option<&'cx Typed> {
        let res = self.get_resultid()?;
        Some(&self.cx[res])
    }
    /// Store the result of fetching this import.
    pub fn set_result(&self, res: Typed) -> ImportResultId {
        let res = self.cx.push_import_result(res);
        self.set_resultid(res);
        res
    }
}

impl<'cx> std::ops::Deref for Ctxt<'cx> {
    type Target = &'cx CtxtS<'cx>;
    fn deref(&self) -> &&'cx CtxtS<'cx> {
        &self.0
    }
}

impl<'cx> std::ops::Index<ImportId> for CtxtS<'cx> {
    type Output = StoredImport<'cx>;
    fn index(&self, id: ImportId) -> &StoredImport<'cx> {
        &self.imports[id.0]
    }
}
impl<'cx> std::ops::Index<ImportResultId> for CtxtS<'cx> {
    type Output = Typed;
    fn index(&self, id: ImportResultId) -> &Typed {
        &self.import_results[id.0]
    }
}

/// Empty impl, because `FrozenVec` does not implement `Debug` and I can't be bothered to do it
/// myself.
impl<'cx> std::fmt::Debug for Ctxt<'cx> {
    fn fmt(&self, _: &mut std::fmt::Formatter) -> std::fmt::Result {
        Ok(())
    }
}