summaryrefslogtreecommitdiff
path: root/dhall/src/semantics/tck/env.rs
blob: 79900597837ffc6d5358dcae8f8067a74fb01a8c (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
119
120
121
122
123
124
125
126
127
128
use crate::semantics::{AlphaVar, NzEnv, NzVar, Type, ValEnv, Value};
use crate::syntax::{Label, V};

/// Environment for indexing variables.
#[derive(Debug, Clone, Copy)]
pub(crate) struct VarEnv {
    size: usize,
}

/// Environment for resolving names.
#[derive(Debug, Clone)]
pub(crate) struct NameEnv {
    names: Vec<Label>,
}

/// Environment for typing expressions.
#[derive(Debug, Clone)]
pub(crate) struct TyEnv {
    names: NameEnv,
    items: ValEnv<Type>,
}

impl VarEnv {
    pub fn new() -> Self {
        VarEnv { size: 0 }
    }
    pub fn size(&self) -> usize {
        self.size
    }
    pub fn insert(&self) -> Self {
        VarEnv {
            size: self.size + 1,
        }
    }
    pub fn lookup(&self, var: &NzVar) -> AlphaVar {
        self.lookup_fallible(var).unwrap()
    }
    pub fn lookup_fallible(&self, var: &NzVar) -> Option<AlphaVar> {
        let idx = self.size.checked_sub(var.idx() + 1)?;
        Some(AlphaVar::new(idx))
    }
}

impl NameEnv {
    pub fn new() -> Self {
        NameEnv { names: Vec::new() }
    }
    pub fn as_varenv(&self) -> VarEnv {
        VarEnv {
            size: self.names.len(),
        }
    }

    pub fn insert(&self, x: &Label) -> Self {
        let mut env = self.clone();
        env.insert_mut(x);
        env
    }
    pub fn insert_mut(&mut self, x: &Label) {
        self.names.push(x.clone())
    }
    pub fn remove_mut(&mut self) {
        self.names.pop();
    }

    pub fn unlabel_var(&self, var: &V) -> Option<AlphaVar> {
        let V(name, idx) = var;
        let (idx, _) = self
            .names
            .iter()
            .rev()
            .enumerate()
            .filter(|(_, n)| *n == name)
            .nth(*idx)?;
        Some(AlphaVar::new(idx))
    }
    pub fn label_var(&self, var: &AlphaVar) -> V {
        let name = &self.names[self.names.len() - 1 - var.idx()];
        let idx = self
            .names
            .iter()
            .rev()
            .take(var.idx())
            .filter(|n| *n == name)
            .count();
        V(name.clone(), idx)
    }
}

impl TyEnv {
    pub fn new() -> Self {
        TyEnv {
            names: NameEnv::new(),
            items: ValEnv::new(),
        }
    }
    pub fn as_varenv(&self) -> VarEnv {
        self.names.as_varenv()
    }
    pub fn to_nzenv(&self) -> NzEnv {
        self.items.discard_types()
    }
    pub fn as_nameenv(&self) -> &NameEnv {
        &self.names
    }

    pub fn insert_type(&self, x: &Label, ty: Type) -> Self {
        TyEnv {
            names: self.names.insert(x),
            items: self.items.insert_type(ty),
        }
    }
    pub fn insert_value(&self, x: &Label, e: Value, ty: Type) -> Self {
        TyEnv {
            names: self.names.insert(x),
            items: self.items.insert_value(e, ty),
        }
    }
    pub fn lookup(&self, var: &AlphaVar) -> Type {
        self.items.lookup_ty(&var)
    }
}

impl<'a> From<&'a TyEnv> for NzEnv {
    fn from(x: &'a TyEnv) -> Self {
        x.to_nzenv()
    }
}