ryna/structures/
variable_map.rs

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
129
130
131
use rustc_hash::{FxHashMap, FxHashSet};

use crate::types::Type;

#[derive(Clone)]
struct VariableContext {
    is_base: bool,
    names: FxHashMap<String, usize>,
    order: Vec<String>,                 // In declaration order
    vars: Vec<(usize, Type)>            // In declaration order
}

impl VariableContext {
    fn new(is_base: bool) -> Self {
        Self { is_base, vars: vec!(), order: vec!(), names: FxHashMap::default() }
    }

    fn contains(&self, name: &String) -> bool {
        self.names.contains_key(name)
    }

    fn get(&self, name: &String) -> Option<&(usize, Type)> {
        match self.names.get(name) {
            Some(idx) => Some(&self.vars[*idx]),
            None => None,
        }
    }

    fn define_var(&mut self, name: String, idx: usize, t: Type) {
        if !self.contains(&name) {
            self.names.entry(name.clone()).or_insert(self.vars.len());
            self.order.push(name);
            self.vars.push((idx, t));
        }
    }
}

#[derive(Clone)]
pub struct VariableMap {
    counter: usize,
    contexts: Vec<VariableContext>
}

impl Default for VariableMap {
    fn default() -> Self {
        Self::new()
    }
}

impl VariableMap {
    pub fn new() -> Self {
        VariableMap { contexts: vec!(), counter: 0 }
    }

    pub fn depth(&self) -> usize {
        self.contexts.len()
    }

    pub fn add_context(&mut self, is_base: bool) {
        self.contexts.push(VariableContext::new(is_base));
    } 

    pub fn remove_context(&mut self) {
        self.contexts.pop().unwrap();
    }

    pub fn define_var(&mut self, name: String, idx: usize, t: Type) -> usize {
        self.contexts.last_mut().unwrap().define_var(name, idx, t);

        self.contexts.len() - 1 // Will never underflow, otherwise it would panic in the previous line
    }

    pub fn count_up(&mut self) -> usize {
        self.counter += 1;
        self.counter
    }

    pub fn is_var_defined(&mut self, name: &String) -> bool {
        for ctx in self.contexts.iter().rev() {
            if ctx.contains(name) {
                return true;
            }
        }

        false
    }

    pub fn is_var_defined_in_last_ctx(&mut self, name: &String) -> bool {
        self.contexts.last().unwrap().contains(name)
    }

    pub fn get_var(&self, name: &String) -> Option<(usize, &(usize, Type))> {
        for (i, ctx) in self.contexts.iter().enumerate().rev() {
            if let Some(v) = ctx.get(name) {
                return Some((i, v));
            }
        }

        None
    }

    pub fn num_vars(&self) -> usize {
        self.contexts.iter().map(|i| i.vars.len()).sum()
    }

    pub fn for_each_last_ctx<T: FnMut(usize, &String, &Type)>(&self, mut f: T) {
        let last_ctx = self.contexts.last().unwrap();

        for n in last_ctx.order.iter().rev() {
            let (i, t) = &last_ctx.vars[*last_ctx.names.get(n).unwrap()];
            f(*i, n, t);
        }
    }

    pub fn for_each_until_base<T: FnMut(usize, &String, &Type)>(&self, mut f: T) {
        for ctx in self.contexts.iter().rev() {
            for n in ctx.order.iter().rev() {
                let (i, t) = &ctx.vars[*ctx.names.get(n).unwrap()];
                f(*i, n, t);
            }

            if ctx.is_base {
                break;
            }
        }
    }

    pub fn var_names(&self) -> FxHashSet<&String> {
        self.contexts.iter().rev().flat_map(|i| i.names.keys()).collect()
    }
}