rem_utils/
labelling.rs

1use std::any::Any;
2use std::any::TypeId;
3use std::borrow::Borrow;
4use std::collections::hash_map::DefaultHasher;
5use std::collections::HashMap;
6use std::hash::Hash;
7use std::hash::Hasher;
8use std::ops::Index;
9
10use ena::unify::UnifyKey;
11
12// https://stackoverflow.com/questions/64838355/how-do-i-create-a-hashmap-with-type-erased-keys
13/// Type erasing keys
14pub trait ASTKey {
15    fn eq(&self, other: &dyn ASTKey) -> bool;
16    fn hash(&self) -> u64;
17    fn as_any(&self) -> &dyn Any;
18}
19
20impl<T: Eq + Hash + 'static> ASTKey for T {
21    fn eq(&self, other: &dyn ASTKey) -> bool {
22        if let Some(other) = other.as_any().downcast_ref::<T>() {
23            self == other
24        } else {
25            false
26        }
27    }
28    fn hash(&self) -> u64 {
29        let mut h = DefaultHasher::new();
30        Hash::hash(&(TypeId::of::<T>(), self), &mut h);
31        h.finish()
32    }
33
34    fn as_any(&self) -> &dyn Any {
35        self
36    }
37}
38
39impl<'a> PartialEq for &'a dyn ASTKey {
40    fn eq(&self, other: &Self) -> bool {
41        ASTKey::eq(*self, *other)
42    }
43}
44
45impl<'a> Eq for &'a dyn ASTKey {}
46
47impl<'a> Hash for &'a dyn ASTKey {
48    fn hash<H: Hasher>(&self, state: &mut H) {
49        let key_hash = ASTKey::hash(*self);
50        state.write_u64(key_hash)
51    }
52}
53
54fn eq_box(elt_a: &Box<dyn ASTKey>, elt_b: &Box<dyn ASTKey>) -> bool {
55    ASTKey::eq(&*elt_a, &*elt_b.borrow())
56}
57
58fn hash_box<H: Hasher>(elt: &Box<dyn ASTKey>, state: &mut H) {
59    Hash::hash(&elt, state)
60}
61
62impl Hash for Box<dyn ASTKey> {
63    fn hash<H: Hasher>(&self, state: &mut H) {
64        hash_box(self, state)
65    }
66}
67
68impl PartialEq for Box<dyn ASTKey> {
69    fn eq(&self, other: &Self) -> bool {
70        eq_box(self, other)
71    }
72}
73
74impl Eq for Box<dyn ASTKey> {}
75
76/// Generic Scoped Context, maps identifiers to labels
77#[derive(Debug)]
78pub struct ScopedContext<K: Eq + Hash, L>(Vec<HashMap<K, L>>);
79
80impl<K: Eq + Hash, L> Default for ScopedContext<K, L> {
81    fn default() -> Self {
82        ScopedContext(vec![HashMap::new()])
83    }
84}
85
86impl<'a, 'b, K: Eq + Hash, L> Index<&'a K> for ScopedContext<K, &'b L> {
87    type Output = L;
88
89    fn index(&self, index: &'a K) -> &'b Self::Output {
90        self.lookup(index).unwrap()
91    }
92}
93
94impl<K: Eq + Hash, L> ScopedContext<K, L> {
95    pub fn open_scope(&mut self) {
96        self.0.push(HashMap::new())
97    }
98    pub fn close_scope(&mut self) {
99        self.0.pop();
100    }
101
102    pub fn add_binding(&mut self, var: K, value: L) {
103        self.0.last_mut().unwrap().insert(var, value);
104    }
105}
106
107impl<K: Eq + Hash, L: Clone> ScopedContext<K, L> {
108    pub fn lookup(&self, ident: &K) -> Option<L> {
109        for table in self.0.iter().rev() {
110            match table.get(ident) {
111                Some(result) => return Some(result.clone()),
112                _ => (),
113            }
114        }
115        None
116    }
117}
118
119/// Type encoding labels of an AST
120#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
121pub struct Label(usize);
122
123impl std::fmt::Display for Label {
124    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125        write!(f, "A{}", self.0)
126    }
127}
128
129impl Label {
130    pub fn new() -> Self {
131        Label(0)
132    }
133    pub fn incr(&mut self) {
134        self.0 += 1
135    }
136    pub fn of_raw(v: usize) -> Self {
137        Label(v)
138    }
139    pub fn to_raw(self) -> usize {
140        self.0
141    }
142}
143
144impl UnifyKey for Label {
145    type Value = Option<crate::typ::RustType>;
146
147    fn index(&self) -> u32 {
148        self.0 as u32
149    }
150
151    fn from_index(u: u32) -> Self {
152        Label(u as usize)
153    }
154
155    fn tag() -> &'static str {
156        todo!()
157    }
158}