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
use std::collections::{HashMap, HashSet};
use serde::{Deserialize, Serialize};
pub const NS_PARAM: &str = "_param";
pub const NS_FUNC: &str = "_func";
#[derive(Default, Serialize, Deserialize, Clone)]
pub struct Scope {
pub(super) variables: HashMap<String, HashSet<usize>>,
}
impl Scope {
pub(super) fn add(&mut self, ident: String, id: usize) {
let decls = self.variables.entry(ident.clone()).or_default();
decls.clear();
decls.insert(id);
self.cascade_variable(ident.as_str());
}
pub(super) fn add_function(&mut self, name: String, id: usize) {
self.add(format!("{NS_FUNC}.{name}"), id);
}
pub(super) fn cascade_variable(&mut self, ident: &str) {
let id = *self.variables[ident].iter().next().unwrap();
let (_, var_name) = split_var_name(ident);
let decls = self.variables.entry(var_name.to_string()).or_default();
decls.insert(id);
}
pub(super) fn clear(&mut self) {
let mut to_remove = HashSet::<usize>::new();
self.variables.retain(|name, decls| {
let remove = name.starts_with(NS_PARAM) || name.ends_with(".*") || name == "*";
if remove {
to_remove.extend(decls.iter());
}
!remove
});
self.variables.retain(|_, decls| {
decls.retain(|d| !to_remove.contains(d));
!decls.is_empty()
});
}
}
pub fn split_var_name(ident: &str) -> (&str, &str) {
ident.rsplit_once('.').unwrap_or(("", ident))
}